diff --git a/api/service/transactionApiService.go b/api/service/transactionApiService.go index a04eb2b38..bb9a4a5ac 100644 --- a/api/service/transactionApiService.go +++ b/api/service/transactionApiService.go @@ -227,7 +227,6 @@ func (ts *TransactionService) PostTransaction( ) (*model.Transaction, error) { var ( txBytes = req.GetTransactionBytes() - txType transaction.TypeAction tx *model.Transaction err error tpsProcessed, @@ -277,44 +276,11 @@ func (ts *TransactionService) PostTransaction( return nil, status.Error(codes.Internal, err.Error()) } // Validate Tx - txType, err = ts.ActionTypeSwitcher.GetTransactionType(tx) - if err != nil { - return nil, status.Error(codes.Internal, err.Error()) - } if err = ts.MempoolService.ValidateMempoolTransaction(tx); err != nil { return nil, status.Error(codes.Internal, err.Error()) } - // Apply Unconfirmed - err = ts.Query.BeginTx() - if err != nil { - return nil, status.Error(codes.Internal, err.Error()) - } - - // TODO: repetitive way - escrowable, ok := txType.Escrowable() - switch ok { - case true: - err = escrowable.EscrowApplyUnconfirmed() - default: - err = txType.ApplyUnconfirmed() - } - if err != nil { - errRollback := ts.Query.RollbackTx() - if errRollback != nil { - return nil, status.Error(codes.Internal, errRollback.Error()) - } - return nil, status.Error(codes.Internal, err.Error()) - } - // Save to mempool - err = ts.MempoolService.AddMempoolTransaction(tx, txBytes) - if err != nil { - errRollback := ts.Query.RollbackTx() - if errRollback != nil { - return nil, status.Error(codes.Internal, errRollback.Error()) - } - return nil, status.Error(codes.Internal, err.Error()) - } - err = ts.Query.CommitTx() + // process validated received transction + err = ts.MempoolService.ReceivedTransactionFromWallet(tx, txBytes) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/api/service/transactionApiService_test.go b/api/service/transactionApiService_test.go index 00598cf86..54fc0ec8f 100644 --- a/api/service/transactionApiService_test.go +++ b/api/service/transactionApiService_test.go @@ -5,17 +5,17 @@ package service import ( "database/sql" "errors" - "github.com/zoobc/zoobc-core/common/crypto" - "github.com/zoobc/zoobc-core/common/feedbacksystem" - "github.com/zoobc/zoobc-core/common/storage" "reflect" "testing" "github.com/DATA-DOG/go-sqlmock" "github.com/sirupsen/logrus" "github.com/zoobc/zoobc-core/common/chaintype" + "github.com/zoobc/zoobc-core/common/crypto" + "github.com/zoobc/zoobc-core/common/feedbacksystem" "github.com/zoobc/zoobc-core/common/model" "github.com/zoobc/zoobc-core/common/query" + "github.com/zoobc/zoobc-core/common/storage" "github.com/zoobc/zoobc-core/common/transaction" "github.com/zoobc/zoobc-core/core/service" "github.com/zoobc/zoobc-core/observer" @@ -107,11 +107,11 @@ func (*mockTxTypeSuccess) Validate(bool) error { return nil } -func (*mockTxTypeApplyUnconfirmedFail) ApplyUnconfirmed() error { +func (*mockTxTypeApplyUnconfirmedFail) ApplyUnconfirmed(bool) error { return errors.New("mockError:ApplyUnconfirmedFail") } -func (*mockTxTypeSuccess) ApplyUnconfirmed() error { +func (*mockTxTypeSuccess) ApplyUnconfirmed(bool) error { return nil } @@ -127,7 +127,10 @@ func (*mockMempoolServiceFailValidate) ValidateMempoolTransaction(mpTx *model.Tr return errors.New("mockedError") } -func (*mockMempoolServiceSuccess) AddMempoolTransaction(tx *model.Transaction, txBytes []byte) error { +func (*mockMempoolServiceSuccess) ReceivedTransactionFromWallet( + receivedTx *model.Transaction, + receivedTxBytes []byte, +) error { return nil } @@ -227,7 +230,7 @@ func TestNewTransactionService(t *testing.T) { ); !reflect.DeepEqual(got, tt.want) { t.Errorf("NewTransactionService() = %v, want %v", got, tt.want) } - defer resetTransactionService() + resetTransactionService() }) } } @@ -271,6 +274,9 @@ type ( mockCacheStorageAlwaysSuccess struct { storage.CacheStorageInterface } + mockMempoolServiceReceivedPostTransactionTransactionFromWalletFail struct { + service.MempoolService + } ) func (*mockCacheStorageAlwaysSuccess) SetItem(key, item interface{}) error { return nil } @@ -280,6 +286,17 @@ func (*mockCacheStorageAlwaysSuccess) RemoveItem(key interface{}) error { ret func (*mockCacheStorageAlwaysSuccess) GetSize() int64 { return 0 } func (*mockCacheStorageAlwaysSuccess) ClearCache() error { return nil } +func (*mockMempoolServiceReceivedPostTransactionTransactionFromWalletFail) ValidateMempoolTransaction( + mpTx *model.Transaction) error { + return nil +} + +func (*mockMempoolServiceReceivedPostTransactionTransactionFromWalletFail) ReceivedTransactionFromWallet( + receivedTx *model.Transaction, + receivedTxBytes []byte, +) error { + return errors.New("mockedErr") +} func TestTransactionService_PostTransaction(t *testing.T) { var ( @@ -306,20 +323,6 @@ func TestTransactionService_PostTransaction(t *testing.T) { false, true, ) - escrowApprovalTX, escrowApprovalTXBytes := transaction.GetFixtureForSpecificTransaction( - -62373445000112233, - 1581301507, - txAPISenderAccount1, - nil, - 12, - model.TransactionType_ApprovalEscrowTransaction, - &model.ApprovalEscrowTransactionBody{ - Approval: 0, - TransactionID: 0, - }, - false, - true, - ) type fields struct { Query query.ExecutorInterface @@ -361,117 +364,11 @@ func TestTransactionService_PostTransaction(t *testing.T) { want: nil, }, { - name: "PostTransaction:txType.ValidateFail", - fields: fields{ - Query: nil, - ActionTypeSwitcher: &mockTypeSwitcherValidateFail{}, - MempoolService: &mockMempoolServiceFailValidate{}, - Log: mockLog, - TransactionUtil: &transaction.Util{ - MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, - }, - FeedbackStrategy: &feedbacksystem.DummyFeedbackStrategy{}, - }, - args: args{ - chaintype: &chaintype.MainChain{}, - req: &model.PostTransactionRequest{ - TransactionBytes: sendMoneyTxBytes, - }, - }, - wantErr: true, - want: nil, - }, - { - name: "PostTransaction:beginTxFail", + name: "ValidateMempoolTransaction:Fail", fields: fields{ - Query: &mockTransactionExecutorFailBeginTx{}, - ActionTypeSwitcher: &mockTypeSwitcherApplyUnconfirmedFail{}, - Log: mockLog, - MempoolService: &mockMempoolServiceSuccess{}, - TransactionUtil: &transaction.Util{ - MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, - }, - FeedbackStrategy: &feedbacksystem.DummyFeedbackStrategy{}, - }, - args: args{ - chaintype: &chaintype.MainChain{}, - req: &model.PostTransactionRequest{ - TransactionBytes: sendMoneyTxBytes, - }, - }, - wantErr: true, - want: nil, - }, - { - name: "PostTransaction:txType.ApplyUnconfirmedFail", - fields: fields{ - Query: &mockTransactionExecutorSuccess{}, - ActionTypeSwitcher: &mockTypeSwitcherApplyUnconfirmedFail{}, - Log: mockLog, - MempoolService: &mockMempoolServiceSuccess{}, - TransactionUtil: &transaction.Util{ - MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, - }, - FeedbackStrategy: &feedbacksystem.DummyFeedbackStrategy{}, - }, - args: args{ - chaintype: &chaintype.MainChain{}, - req: &model.PostTransactionRequest{ - TransactionBytes: sendMoneyTxBytes, - }, - }, - wantErr: true, - want: nil, - }, - { - name: "PostTransaction:txType.ApplyUnconfirmedFail-RollbackFail", - fields: fields{ - Query: &mockTransactionExecutorRollbackFail{}, - ActionTypeSwitcher: &mockTypeSwitcherApplyUnconfirmedFail{}, - Log: mockLog, - MempoolService: &mockMempoolServiceSuccess{}, - TransactionUtil: &transaction.Util{ - MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, - }, - FeedbackStrategy: &feedbacksystem.DummyFeedbackStrategy{}, - }, - args: args{ - chaintype: &chaintype.MainChain{}, - req: &model.PostTransactionRequest{ - TransactionBytes: sendMoneyTxBytes, - }, - }, - wantErr: true, - want: nil, - }, - { - name: "PostTransaction:txType.AddMempoolTransactionFail", - fields: fields{ - Query: &mockTransactionExecutorSuccess{}, - ActionTypeSwitcher: &mockTypeSwitcherSuccess{}, - MempoolService: &mockMempoolServiceFailAdd{}, - Log: mockLog, - TransactionUtil: &transaction.Util{ - MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, - }, - FeedbackStrategy: &feedbacksystem.DummyFeedbackStrategy{}, - }, - args: args{ - chaintype: &chaintype.MainChain{}, - req: &model.PostTransactionRequest{ - TransactionBytes: sendMoneyTxBytes, - }, - }, - wantErr: true, - want: nil, - }, - { - name: "PostTransaction:txType.AddMempoolTransactionFail-RollbackFail", - fields: fields{ - Query: &mockTransactionExecutorRollbackFail{}, - ActionTypeSwitcher: &mockTypeSwitcherSuccess{}, - MempoolService: &mockMempoolServiceFailAdd{}, - Log: mockLog, + MempoolService: &mockMempoolServiceFailValidate{}, + Observer: observer.NewObserver(), + Log: mockLog, TransactionUtil: &transaction.Util{ MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, }, @@ -480,19 +377,18 @@ func TestTransactionService_PostTransaction(t *testing.T) { args: args{ chaintype: &chaintype.MainChain{}, req: &model.PostTransactionRequest{ - TransactionBytes: sendMoneyTxBytes, + TransactionBytes: transactionBytes, }, }, wantErr: true, want: nil, }, { - name: "PostTransaction:txType.AddMempoolTransactionFail-RollbackFail", + name: "ReceivedTransactionFromWallet:Fail", fields: fields{ - Query: &mockTransactionExecutorCommitFail{}, - ActionTypeSwitcher: &mockTypeSwitcherSuccess{}, - MempoolService: &mockMempoolServiceSuccess{}, - Log: mockLog, + MempoolService: &mockMempoolServiceReceivedPostTransactionTransactionFromWalletFail{}, + Observer: observer.NewObserver(), + Log: mockLog, TransactionUtil: &transaction.Util{ MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, }, @@ -501,20 +397,18 @@ func TestTransactionService_PostTransaction(t *testing.T) { args: args{ chaintype: &chaintype.MainChain{}, req: &model.PostTransactionRequest{ - TransactionBytes: sendMoneyTxBytes, + TransactionBytes: transactionBytes, }, }, wantErr: true, want: nil, }, { - name: "PostTransaction:txType.Success", + name: "Success", fields: fields{ - Query: &mockTransactionExecutorSuccess{}, - ActionTypeSwitcher: &mockTypeSwitcherSuccess{}, - MempoolService: &mockMempoolServiceSuccess{}, - Observer: observer.NewObserver(), - Log: mockLog, + MempoolService: &mockMempoolServiceSuccess{}, + Observer: observer.NewObserver(), + Log: mockLog, TransactionUtil: &transaction.Util{ MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, }, @@ -529,29 +423,6 @@ func TestTransactionService_PostTransaction(t *testing.T) { wantErr: false, want: txTypeSuccess, }, - { - name: "WantError:ValidateMempoolFail1", - fields: fields{ - Query: &mockQueryExecutorPostApprovalEscrowTX{}, - Signature: nil, - ActionTypeSwitcher: &transaction.TypeSwitcher{ - Executor: &mockQueryExecutorPostApprovalEscrowTX{}, - }, - MempoolService: &mockMempoolServicePostApprovalEscrowTXSuccess{}, - Observer: observer.NewObserver(), - TransactionUtil: &transaction.Util{ - MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, - }, - FeedbackStrategy: &feedbacksystem.DummyFeedbackStrategy{}, - }, - args: args{ - chaintype: &chaintype.MainChain{}, - req: &model.PostTransactionRequest{ - TransactionBytes: escrowApprovalTXBytes, - }, - }, - want: escrowApprovalTX, - }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/cmd/block/blockGenerator.go b/cmd/block/blockGenerator.go index 67dffd55f..d7264968c 100644 --- a/cmd/block/blockGenerator.go +++ b/cmd/block/blockGenerator.go @@ -2,6 +2,8 @@ package block import ( "fmt" + "strings" + "time" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -21,8 +23,6 @@ import ( "github.com/zoobc/zoobc-core/core/smith/strategy" coreUtil "github.com/zoobc/zoobc-core/core/util" "github.com/zoobc/zoobc-core/observer" - "strings" - "time" ) type ( @@ -119,7 +119,7 @@ func initialize( panic(err) } queryExecutor = query.NewQueryExecutor(db) - mempoolStorage := storage.NewMempoolStorage() + mempoolStorage := storage.NewMempoolStorage(monitoring.TypeMempoolCacheStorage, monitoring.TypeMempoolCountCacheStorage) actionSwitcher := &transaction.TypeSwitcher{ Executor: queryExecutor, @@ -163,6 +163,8 @@ func initialize( blocksStorage, mempoolStorage, nil, + nil, + nil, ) nodeAddressInfoService := service.NewNodeAddressInfoService( queryExecutor, diff --git a/cmd/genesisblock/cmd.go b/cmd/genesisblock/cmd.go index 3aac80659..828e69664 100644 --- a/cmd/genesisblock/cmd.go +++ b/cmd/genesisblock/cmd.go @@ -6,9 +6,6 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/zoobc/zoobc-core/common/accounttype" - "github.com/zoobc/zoobc-core/common/crypto" - "github.com/zoobc/zoobc-core/common/signaturetype" "io/ioutil" "log" "os" @@ -18,16 +15,18 @@ import ( "text/template" "time" - "github.com/zoobc/zoobc-core/common/monitoring" - "github.com/spf13/cobra" "github.com/zoobc/lib/address" + "github.com/zoobc/zoobc-core/common/accounttype" "github.com/zoobc/zoobc-core/common/auth" "github.com/zoobc/zoobc-core/common/chaintype" "github.com/zoobc/zoobc-core/common/constant" + "github.com/zoobc/zoobc-core/common/crypto" "github.com/zoobc/zoobc-core/common/database" "github.com/zoobc/zoobc-core/common/model" + "github.com/zoobc/zoobc-core/common/monitoring" "github.com/zoobc/zoobc-core/common/query" + "github.com/zoobc/zoobc-core/common/signaturetype" "github.com/zoobc/zoobc-core/common/storage" "github.com/zoobc/zoobc-core/common/transaction" "github.com/zoobc/zoobc-core/common/util" @@ -507,7 +506,7 @@ func getGenesisBlockID(genesisEntries []genesisEntry) (mainBlockID, spineBlockID var ( signature = crypto.NewSignature() nodeAuthValidationService = auth.NewNodeAuthValidation(signature) - mempoolStorage = storage.NewMempoolStorage() + mempoolStorage = storage.NewMempoolStorage(monitoring.TypeMempoolCacheStorage, monitoring.TypeMempoolCountCacheStorage) genesisConfig []constant.GenesisConfigEntry ) activeNodeRegistryCacheStorage := storage.NewNodeRegistryCacheStorage( diff --git a/cmd/snapshot/snapshot.go b/cmd/snapshot/snapshot.go index 85754724b..ee04b972d 100644 --- a/cmd/snapshot/snapshot.go +++ b/cmd/snapshot/snapshot.go @@ -3,23 +3,23 @@ package snapshot import ( "crypto/sha256" "database/sql" - "github.com/zoobc/zoobc-core/common/crypto" "math/rand" "os" - "github.com/zoobc/zoobc-core/common/util" - "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/ugorji/go/codec" "github.com/zoobc/zoobc-core/common/auth" "github.com/zoobc/zoobc-core/common/chaintype" "github.com/zoobc/zoobc-core/common/constant" + "github.com/zoobc/zoobc-core/common/crypto" "github.com/zoobc/zoobc-core/common/database" "github.com/zoobc/zoobc-core/common/model" + "github.com/zoobc/zoobc-core/common/monitoring" "github.com/zoobc/zoobc-core/common/query" "github.com/zoobc/zoobc-core/common/storage" "github.com/zoobc/zoobc-core/common/transaction" + "github.com/zoobc/zoobc-core/common/util" "github.com/zoobc/zoobc-core/core/service" "golang.org/x/crypto/sha3" ) @@ -77,7 +77,7 @@ func newSnapshotProcess() func(ccmd *cobra.Command, args []string) { snapshotFile, ) executor = query.NewQueryExecutor(sqliteDB) - mempoolStorage := storage.NewMempoolStorage() + mempoolStorage := storage.NewMempoolStorage(monitoring.TypeMempoolCacheStorage, monitoring.TypeMempoolCountCacheStorage) nodeAuthValidation := auth.NewNodeAuthValidation(signature) snapshotMainService := service.NewSnapshotMainBlockService( snapshotFile, @@ -227,7 +227,7 @@ func storingPayloadProcess() func(ccmd *cobra.Command, args []string) { var ( signature = crypto.NewSignature() nodeAuthValidationService = auth.NewNodeAuthValidation(signature) - mempoolStorage = storage.NewMempoolStorage() + mempoolStorage = storage.NewMempoolStorage(monitoring.TypeMempoolCacheStorage, monitoring.TypeMempoolCountCacheStorage) snapshotFileInfo *model.SnapshotFileInfo sqliteInstance = database.NewSqliteDB() mainChain = &chaintype.MainChain{} diff --git a/common/constant/mempool.go b/common/constant/mempool.go index fbf3d77d5..441ec96fe 100644 --- a/common/constant/mempool.go +++ b/common/constant/mempool.go @@ -15,4 +15,11 @@ const ( TxCachedTimeout = 300 // Gap of the CleanTimedoutTxCandidateThread CleanTimedoutBlockTxCachedThreadGap = 10 + // MaxMoveMempoolTrasaction is maximum mempool to move from full cache to normal cache + MempoolMaxMoveTrasactions = 2 * MaxNumberOfTransactionsInBlock + // MempoolMovePeriod the period to move full cahce mempool into normal cache + MempoolMoveFullCachePeriod = 4 * time.Second + // MempoolMaxTimeGapBecameFullCacheTransaction the maximimum time gap between incoming transaction + // to determine whether the incoming transaction became full cache mempool or not + MempoolMaxTimeGapBecameFullCacheTransaction = 2 ) diff --git a/common/constant/transaction.go b/common/constant/transaction.go index 822bb0f53..43eaca8fb 100644 --- a/common/constant/transaction.go +++ b/common/constant/transaction.go @@ -2,7 +2,7 @@ package constant import "time" -var ( +const ( MaxMessageLength = 256 MaxNumberOfTransactionsInBlock = 330 MinTransactionSizeInBlock = 176 diff --git a/common/monitoring/metricsMonitoring.go b/common/monitoring/metricsMonitoring.go index 77eba8af3..f36df29d1 100644 --- a/common/monitoring/metricsMonitoring.go +++ b/common/monitoring/metricsMonitoring.go @@ -573,11 +573,11 @@ func SetBlockProcessTime(timeMs int64) { blockProcessTimeGaugeVector.WithLabelValues("BlockProcessTime").Set(float64(timeMs)) } -func SetMempoolTransactionCount(mempoolTxCount int) { +func SetMempoolTransactionCount(cacheType CacheStorageType, mempoolTxCount int) { if !isMonitoringActive { return } - mempoolTransactionCountGaugeVector.WithLabelValues("MempoolTransactionCount").Set(float64(mempoolTxCount)) + mempoolTransactionCountGaugeVector.WithLabelValues(string(cacheType)).Set(float64(mempoolTxCount)) } func IncrementGoRoutineActivity(activityName string) { @@ -667,15 +667,18 @@ type ( // Cache Storage environments // Please add new one when add new cache storage instance var ( - TypeMempoolCacheStorage CacheStorageType = "mempools" - TypeBatchReceiptCacheStorage CacheStorageType = "batch_receipts" - TypeScrambleNodeCacheStorage CacheStorageType = "scramble_nodes" - TypeMempoolBackupCacheStorage CacheStorageType = "backup_mempools" - TypeNodeShardCacheStorage CacheStorageType = "node_shards" - TypeNodeAddressInfoCacheStorage CacheStorageType = "node_address_infos" - TypeActiveNodeRegistryStorage CacheStorageType = "node_registry_active" - TypePendingNodeRegistryStorage CacheStorageType = "node_registry_pending" - TypeBlocksCacheStorage CacheStorageType = "blocks_cache_object" + TypeMempoolCacheStorage CacheStorageType = "mempools" + TypeMempoolCountCacheStorage CacheStorageType = "mempools_count" + TypeMempoolUnsaveCacheStorage CacheStorageType = "mempools_unsave" + TypeMempoolUnsaveCountCacheStorage CacheStorageType = "mempools_unsave_count" + TypeBatchReceiptCacheStorage CacheStorageType = "batch_receipts" + TypeScrambleNodeCacheStorage CacheStorageType = "scramble_nodes" + TypeMempoolBackupCacheStorage CacheStorageType = "backup_mempools" + TypeNodeShardCacheStorage CacheStorageType = "node_shards" + TypeNodeAddressInfoCacheStorage CacheStorageType = "node_address_infos" + TypeActiveNodeRegistryStorage CacheStorageType = "node_registry_active" + TypePendingNodeRegistryStorage CacheStorageType = "node_registry_pending" + TypeBlocksCacheStorage CacheStorageType = "blocks_cache_object" ) func SetCacheStorageMetrics(cacheType CacheStorageType, size float64) { diff --git a/common/storage/mempoolStorage.go b/common/storage/mempoolStorage.go index 951664d1c..9ee11577a 100644 --- a/common/storage/mempoolStorage.go +++ b/common/storage/mempoolStorage.go @@ -12,10 +12,13 @@ type ( // MempoolCacheStorage cache layer for mempool transaction MempoolCacheStorage struct { sync.RWMutex - mempoolMap MempoolMap + metricSizeLabel monitoring.CacheStorageType + metricCountLabel monitoring.CacheStorageType + mempoolMap MempoolMap } MempoolCacheObject struct { Tx model.Transaction + TxBytes []byte ArrivalTimestamp int64 FeePerByte int64 TransactionByteSize uint32 @@ -24,9 +27,11 @@ type ( MempoolMap map[int64]MempoolCacheObject ) -func NewMempoolStorage() *MempoolCacheStorage { +func NewMempoolStorage(metricSizeLabel, metricCountLabel monitoring.CacheStorageType) *MempoolCacheStorage { return &MempoolCacheStorage{ - mempoolMap: make(MempoolMap), + mempoolMap: make(MempoolMap), + metricSizeLabel: metricSizeLabel, + metricCountLabel: metricCountLabel, } } @@ -39,10 +44,10 @@ func (m *MempoolCacheStorage) SetItem(key, item interface{}) error { if !ok { return blocker.NewBlocker(blocker.ValidationErr, "WrongType item") } - m.mempoolMap[keyInt64] = mempoolMap + m.mempoolMap[keyInt64] = m.mempoolCopy(mempoolMap) if monitoring.IsMonitoringActive() { - monitoring.SetCacheStorageMetrics(monitoring.TypeMempoolCacheStorage, float64(m.size())) - monitoring.SetMempoolTransactionCount(len(m.mempoolMap)) + monitoring.SetCacheStorageMetrics(m.metricSizeLabel, float64(m.size())) + monitoring.SetMempoolTransactionCount(m.metricCountLabel, len(m.mempoolMap)) } } else { return blocker.NewBlocker(blocker.ValidationErr, "WrongType item") @@ -62,7 +67,7 @@ func (m *MempoolCacheStorage) GetItem(key, item interface{}) error { if !ok { return blocker.NewBlocker(blocker.ValidationErr, "WrongType item") } - *txCopy = m.mempoolMap[keyInt64] + *txCopy = m.mempoolCopy(m.mempoolMap[keyInt64]) return nil } return blocker.NewBlocker(blocker.ValidationErr, "WrongType Key") @@ -79,7 +84,7 @@ func (m *MempoolCacheStorage) GetAllItems(item interface{}) error { return blocker.NewBlocker(blocker.ValidationErr, "WrongTypeItem") } for k, tx := range m.mempoolMap { - itemCopy[k] = tx + itemCopy[k] = m.mempoolCopy(tx) } return nil } @@ -107,8 +112,8 @@ func (m *MempoolCacheStorage) RemoveItem(keys interface{}) error { delete(m.mempoolMap, id) } if monitoring.IsMonitoringActive() { - monitoring.SetCacheStorageMetrics(monitoring.TypeMempoolCacheStorage, float64(m.size())) - monitoring.SetMempoolTransactionCount(len(m.mempoolMap)) + monitoring.SetCacheStorageMetrics(m.metricSizeLabel, float64(m.size())) + monitoring.SetMempoolTransactionCount(m.metricCountLabel, len(m.mempoolMap)) } return nil } @@ -132,7 +137,14 @@ func (m *MempoolCacheStorage) GetSize() int64 { func (m *MempoolCacheStorage) ClearCache() error { m.mempoolMap = make(MempoolMap) if monitoring.IsMonitoringActive() { - monitoring.SetCacheStorageMetrics(monitoring.TypeMempoolCacheStorage, 0) + monitoring.SetCacheStorageMetrics(m.metricSizeLabel, 0) + monitoring.SetMempoolTransactionCount(m.metricCountLabel, len(m.mempoolMap)) } return nil } + +func (m *MempoolCacheStorage) mempoolCopy(mempoolCacheObject MempoolCacheObject) MempoolCacheObject { + var mempoolCacheObjectCopy = mempoolCacheObject + copy(mempoolCacheObjectCopy.TxBytes, mempoolCacheObject.TxBytes) + return mempoolCacheObjectCopy +} diff --git a/common/storage/spendableBalanceStorage.go b/common/storage/spendableBalanceStorage.go new file mode 100644 index 000000000..bb6ae423f --- /dev/null +++ b/common/storage/spendableBalanceStorage.go @@ -0,0 +1,215 @@ +package storage + +import ( + "bytes" + "encoding/gob" + "fmt" + "sync" + + "github.com/zoobc/zoobc-core/common/blocker" +) + +type ( + // SpendableBalanceStorage cache for spendable balance + SpendableBalanceStorage struct { + sync.RWMutex + transactionalLock sync.RWMutex + isInTransaction bool + transactionalSpendableBalances map[string]int64 + spendableBalances map[string]int64 + } + + spendableBalanceCacheObject struct { + AccountAddress []byte + SpendableBalance int64 + } +) + +func NewSpendableBalanceStorage() *SpendableBalanceStorage { + return &SpendableBalanceStorage{ + spendableBalances: make(map[string]int64), + } +} + +func (sp *SpendableBalanceStorage) SetItem(key, item interface{}) error { + account, ok := key.([]byte) + if !ok { + return blocker.NewBlocker(blocker.ValidationErr, "WrongTypeKeyExpected:[]byte") + } + spendableBalance, ok := item.(int64) + if !ok { + return blocker.NewBlocker(blocker.ValidationErr, "WrongTypeKeyExpected:int64") + } + sp.Lock() + sp.spendableBalances[fmt.Sprintf("%q", account)] = spendableBalance + sp.Unlock() + return nil +} + +func (sp *SpendableBalanceStorage) SetItems(_ interface{}) error { + return nil +} + +func (sp *SpendableBalanceStorage) GetItem(key, item interface{}) error { + account, ok := key.([]byte) + if !ok { + return blocker.NewBlocker(blocker.ValidationErr, "WrongTypeKeyExpected:[]byte") + } + spendableBalance, ok := item.(*int64) + if !ok { + return blocker.NewBlocker(blocker.ValidationErr, "WrongTypeKeyExpected:*int64") + } + + if sp.isInTransaction { + // return from transactional list + sp.transactionalLock.RLock() + *spendableBalance = sp.transactionalSpendableBalances[fmt.Sprintf("%q", account)] + sp.transactionalLock.RUnlock() + } else { + // return from normal list + sp.RLock() + *spendableBalance = sp.spendableBalances[fmt.Sprintf("%q", account)] + sp.RUnlock() + } + return nil +} + +func (sp *SpendableBalanceStorage) GetAllItems(item interface{}) error { + spendableBalancesObject, ok := item.(*[]spendableBalanceCacheObject) + if !ok { + return blocker.NewBlocker(blocker.ValidationErr, "WrongTypeKeyExpected:*[]spendableBalanceCacheObject") + } + if sp.isInTransaction { + sp.transactionalLock.RLock() + for accountStr, spendable := range sp.transactionalSpendableBalances { + *spendableBalancesObject = append(*spendableBalancesObject, spendableBalanceCacheObject{ + AccountAddress: []byte(accountStr), + SpendableBalance: spendable, + }) + } + sp.transactionalLock.RUnlock() + } else { + sp.RLock() + for accountStr, spendable := range sp.spendableBalances { + *spendableBalancesObject = append(*spendableBalancesObject, spendableBalanceCacheObject{ + AccountAddress: []byte(accountStr), + SpendableBalance: spendable, + }) + } + sp.RUnlock() + } + + return nil +} +func (sp *SpendableBalanceStorage) GetTotalItems() int { + return len(sp.spendableBalances) +} + +func (sp *SpendableBalanceStorage) RemoveItem(key interface{}) error { + AccountPubKey, ok := key.([]byte) + if !ok { + return blocker.NewBlocker(blocker.ValidationErr, "WrongTypeKeyExpected:[]byte") + } + sp.Lock() + delete(sp.spendableBalances, fmt.Sprintf("%q", AccountPubKey)) + sp.Unlock() + return nil +} + +func (sp *SpendableBalanceStorage) size() int { + var ( + nBytes bytes.Buffer + enc = gob.NewEncoder(&nBytes) + ) + _ = enc.Encode(sp.spendableBalances) + return nBytes.Len() +} + +func (sp *SpendableBalanceStorage) GetSize() int64 { + return int64(sp.size()) +} +func (sp *SpendableBalanceStorage) ClearCache() error { + sp.spendableBalances = make(map[string]int64) + return nil +} + +// Transactional implementation + +// Begin prepare data to begin doing transactional change to the cache, this implementation +// will never return error +func (sp *SpendableBalanceStorage) Begin() error { + sp.Lock() + sp.transactionalLock.Lock() + defer sp.transactionalLock.Unlock() + sp.isInTransaction = true + sp.transactionalSpendableBalances = make(map[string]int64) + // copy current spendable balance into transaction list + for accountStr, spendableBalance := range sp.spendableBalances { + sp.transactionalSpendableBalances[accountStr] = spendableBalance + } + return nil +} + +func (sp *SpendableBalanceStorage) Commit() error { + // make sure isInTransaction is true + if !sp.isInTransaction { + return blocker.NewBlocker(blocker.ValidationErr, "BeginIsRequired") + } + sp.transactionalLock.Lock() + defer func() { + sp.isInTransaction = false + sp.Unlock() + sp.transactionalLock.Unlock() + }() + // Update all spendable belence from transactional spendable belance + for accountStr, spendableBalance := range sp.transactionalSpendableBalances { + sp.spendableBalances[accountStr] = spendableBalance + } + sp.transactionalSpendableBalances = make(map[string]int64) + return nil +} + +func (sp *SpendableBalanceStorage) Rollback() error { + // make sure isInTransaction is true + if !sp.isInTransaction { + return blocker.NewBlocker(blocker.ValidationErr, "BeginIsRequired") + } + sp.transactionalLock.Lock() + defer func() { + sp.isInTransaction = false + sp.Unlock() + sp.transactionalLock.Unlock() + }() + sp.transactionalSpendableBalances = make(map[string]int64) + return nil +} + +// TxSetItem set individual item +func (sp *SpendableBalanceStorage) TxSetItem(id, item interface{}) error { + // make sure isInTransaction is true + if !sp.isInTransaction { + return blocker.NewBlocker(blocker.ValidationErr, "BeginIsRequired") + } + account, ok := id.([]byte) + if !ok { + return blocker.NewBlocker(blocker.ValidationErr, "WrongTypeKeyExpected:[]byte") + } + spendableBalance, ok := item.(int64) + if !ok { + return blocker.NewBlocker(blocker.ValidationErr, "WrongTypeKeyExpected:int64") + } + sp.transactionalLock.Lock() + sp.transactionalSpendableBalances[fmt.Sprintf("%q", account)] = spendableBalance + sp.transactionalLock.Unlock() + return nil +} + +// TxSetItems currently doesn’t need to set in transactional +func (sp *SpendableBalanceStorage) TxSetItems(items interface{}) error { + return blocker.NewBlocker(blocker.ValidationErr, "NotYetImeplemented") +} + +// TxRemoveItem currently doesn’t need to remove in transactional +func (sp *SpendableBalanceStorage) TxRemoveItem(id interface{}) error { + return blocker.NewBlocker(blocker.ValidationErr, "NotYetImeplemented") +} diff --git a/common/transaction/accountBalanceHelper.go b/common/transaction/accountBalanceHelper.go index 44fd43bd9..4fae230f3 100644 --- a/common/transaction/accountBalanceHelper.go +++ b/common/transaction/accountBalanceHelper.go @@ -7,6 +7,7 @@ import ( "github.com/zoobc/zoobc-core/common/blocker" "github.com/zoobc/zoobc-core/common/model" "github.com/zoobc/zoobc-core/common/query" + "github.com/zoobc/zoobc-core/common/storage" ) type ( @@ -14,6 +15,8 @@ type ( // It better to use with QueryExecutor.BeginTX() AccountBalanceHelperInterface interface { AddAccountSpendableBalance(address []byte, amount int64) error + AddAccountSpendableBalanceInCache(address []byte, amount int64) error + UpdateAccountSpendableBalanceInCache(address []byte, amount int64) error AddAccountBalance(address []byte, amount int64, event model.EventType, blockHeight uint32, transactionID int64, blockTimestamp uint64) error GetBalanceByAccountAddress(accountBalance *model.AccountBalance, address []byte, dbTx bool) error @@ -22,10 +25,11 @@ type ( // AccountBalanceHelper fields for AccountBalanceHelperInterface for transaction helper AccountBalanceHelper struct { // accountBalance cache when get from db, use this for validation only. - accountBalance model.AccountBalance - AccountBalanceQuery query.AccountBalanceQueryInterface - AccountLedgerQuery query.AccountLedgerQueryInterface - QueryExecutor query.ExecutorInterface + accountBalance model.AccountBalance + AccountBalanceQuery query.AccountBalanceQueryInterface + AccountLedgerQuery query.AccountLedgerQueryInterface + QueryExecutor query.ExecutorInterface + SpendableBalanceStorage storage.CacheStorageInterface } ) @@ -33,11 +37,13 @@ func NewAccountBalanceHelper( queryExecutor query.ExecutorInterface, accountBalanceQuery query.AccountBalanceQueryInterface, accountLedgerQuery query.AccountLedgerQueryInterface, + spendableBalanceStorage storage.CacheStorageInterface, ) *AccountBalanceHelper { return &AccountBalanceHelper{ - AccountBalanceQuery: accountBalanceQuery, - AccountLedgerQuery: accountLedgerQuery, - QueryExecutor: queryExecutor, + AccountBalanceQuery: accountBalanceQuery, + AccountLedgerQuery: accountLedgerQuery, + QueryExecutor: queryExecutor, + SpendableBalanceStorage: spendableBalanceStorage, } } @@ -51,12 +57,54 @@ func (abh *AccountBalanceHelper) AddAccountSpendableBalance(address []byte, amou }, ) err := abh.QueryExecutor.ExecuteTransaction(accountBalanceSenderQ, accountBalanceSenderQArgs...) - if err == nil { - abh.accountBalance = model.AccountBalance{} - } return err } +// AddAccountSpendableBalanceInCache to add or update spendable balance in cache storage +func (abh *AccountBalanceHelper) AddAccountSpendableBalanceInCache(address []byte, amount int64) error { + var ( + currentSpendAbleBalance int64 + err = abh.SpendableBalanceStorage.GetItem(address, ¤tSpendAbleBalance) + ) + if err != nil { + return err + } + if currentSpendAbleBalance == 0 { + // get spendable balace from DB + var accountBalance model.AccountBalance + err = abh.GetBalanceByAccountAddress(&accountBalance, address, false) + if err != nil { + return err + } + currentSpendAbleBalance = accountBalance.GetSpendableBalance() + } + newSpendableBalance := currentSpendAbleBalance + amount + return abh.SpendableBalanceStorage.SetItem(address, newSpendableBalance) +} + +/* + UpdateAccountSpendableBalanceInCache to update existing spendable balance in cache storage + - update existing cache spendable balance should be in transactional process +*/ +func (abh *AccountBalanceHelper) UpdateAccountSpendableBalanceInCache(address []byte, amount int64) error { + var ( + spendAbleBalance int64 + err = abh.SpendableBalanceStorage.GetItem(address, &spendAbleBalance) + ) + if err != nil { + return err + } + if spendAbleBalance == 0 { + return nil + } + spendAbleBalance += amount + txSpendableBalanceStorage, ok := abh.SpendableBalanceStorage.(storage.TransactionalCache) + if !ok { + return blocker.NewBlocker(blocker.AppErr, "FailToCastSpendableBalanceStorageAsTransactionalCacheInterface") + } + return txSpendableBalanceStorage.TxSetItem(address, spendAbleBalance) +} + // AddAccountBalance add balance and spendable_balance field to the address provided at blockHeight, must be executed // inside db transaction scope, there process is: // - Add new record into account_balance @@ -91,10 +139,30 @@ func (abh *AccountBalanceHelper) AddAccountBalance( }) queries = append(queries, append([]interface{}{accountLedgerQ}, accountLedgerArgs...)) err := abh.QueryExecutor.ExecuteTransactions(queries) - if err == nil { - abh.accountBalance = model.AccountBalance{} + if err != nil { + return err } - return err + + // check if spendable balance is cached + var spendableBalanceCache int64 + err = abh.SpendableBalanceStorage.GetItem(address, &spendableBalanceCache) + if err != nil { + return err + } + if spendableBalanceCache == 0 { + return nil + } + // updating spendable balance in cache + spendableBalanceCache += amount + txSpendableBalanceStorage, ok := abh.SpendableBalanceStorage.(storage.TransactionalCache) + if !ok { + return blocker.NewBlocker(blocker.AppErr, "FailToCastSpendableBalanceStorageAsTransactionalCacheInterface") + } + err = txSpendableBalanceStorage.TxSetItem(address, spendableBalanceCache) + if err != nil { + return err + } + return nil } // GetBalanceByAccountAddress fetching the balance of an account from database @@ -117,6 +185,18 @@ func (abh *AccountBalanceHelper) GetBalanceByAccountAddress(accountBalance *mode } return blocker.NewBlocker(blocker.ValidationErr, "TXSenderNotFound") } + + // check into spendable balance cache + var spendableBalance int64 + err = abh.SpendableBalanceStorage.GetItem(address, &spendableBalance) + if err != nil { + return err + } + if spendableBalance == 0 { + return nil + } + // use spendable cache when spendable account is cached + accountBalance.SpendableBalance = spendableBalance return nil } @@ -126,18 +206,22 @@ func (abh *AccountBalanceHelper) HasEnoughSpendableBalance(dbTX bool, address [] return abh.accountBalance.GetSpendableBalance() >= compareBalance, nil } var ( - row *sql.Row - accountBalance model.AccountBalance + accountBalance model.AccountBalance + spendableBalance int64 ) - qry, args := abh.AccountBalanceQuery.GetAccountBalanceByAccountAddress(address) - row, err = abh.QueryExecutor.ExecuteSelectRow(qry, dbTX, args...) + // check first into spendable balance cache + err = abh.SpendableBalanceStorage.GetItem(address, &spendableBalance) if err != nil { return enough, err } - err = abh.AccountBalanceQuery.Scan(&accountBalance, row) - if err != nil { - return enough, err + if spendableBalance == 0 { + // check into Database if not cached + err = abh.GetBalanceByAccountAddress(&accountBalance, address, dbTX) + if err != nil { + return enough, err + } + abh.accountBalance = accountBalance + spendableBalance = accountBalance.GetSpendableBalance() } - abh.accountBalance = accountBalance - return accountBalance.GetSpendableBalance() >= compareBalance, nil + return spendableBalance >= compareBalance, nil } diff --git a/common/transaction/accountBalanceHelper_test.go b/common/transaction/accountBalanceHelper_test.go index 5e9e90ab6..167c893b1 100644 --- a/common/transaction/accountBalanceHelper_test.go +++ b/common/transaction/accountBalanceHelper_test.go @@ -6,8 +6,8 @@ import ( "testing" "github.com/zoobc/zoobc-core/common/model" - "github.com/zoobc/zoobc-core/common/query" + "github.com/zoobc/zoobc-core/common/storage" ) type ( @@ -17,6 +17,9 @@ type ( mockAccountBalanceHelperExecutorAddSpendableSuccess struct { query.ExecutorInterface } + mockAccountBalanceHelperSpendableBalanceStorageSuccess struct { + storage.SpendableBalanceStorage + } ) func (*mockAccountBalanceHelperExecutorAddSpendableFail) ExecuteTransaction(query string, args ...interface{}) error { @@ -35,6 +38,10 @@ func (*mockAccountBalanceHelperExecutorAddSpendableSuccess) ExecuteTransactions( return nil } +func (*mockAccountBalanceHelperSpendableBalanceStorageSuccess) GetItem(key, item interface{}) error { + return nil +} + func TestAccountBalanceHelper_AddAccountSpendableBalance(t *testing.T) { type fields struct { AccountBalanceQuery query.AccountBalanceQueryInterface @@ -84,9 +91,10 @@ func TestAccountBalanceHelper_AddAccountSpendableBalance(t *testing.T) { func TestAccountBalanceHelper_AddAccountBalance(t *testing.T) { type fields struct { - AccountBalanceQuery query.AccountBalanceQueryInterface - AccountLedgerQuery query.AccountLedgerQueryInterface - QueryExecutor query.ExecutorInterface + AccountBalanceQuery query.AccountBalanceQueryInterface + AccountLedgerQuery query.AccountLedgerQueryInterface + QueryExecutor query.ExecutorInterface + SpendableBalanceStorage storage.CacheStorageInterface } type args struct { address []byte @@ -112,9 +120,10 @@ func TestAccountBalanceHelper_AddAccountBalance(t *testing.T) { { name: "executeSuccess", fields: fields{ - AccountBalanceQuery: query.NewAccountBalanceQuery(), - AccountLedgerQuery: query.NewAccountLedgerQuery(), - QueryExecutor: &mockAccountBalanceHelperExecutorAddSpendableSuccess{}, + AccountBalanceQuery: query.NewAccountBalanceQuery(), + AccountLedgerQuery: query.NewAccountLedgerQuery(), + QueryExecutor: &mockAccountBalanceHelperExecutorAddSpendableSuccess{}, + SpendableBalanceStorage: &mockAccountBalanceHelperSpendableBalanceStorageSuccess{}, }, args: args{}, wantErr: false, @@ -123,9 +132,10 @@ func TestAccountBalanceHelper_AddAccountBalance(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { abh := &AccountBalanceHelper{ - AccountBalanceQuery: tt.fields.AccountBalanceQuery, - AccountLedgerQuery: tt.fields.AccountLedgerQuery, - QueryExecutor: tt.fields.QueryExecutor, + AccountBalanceQuery: tt.fields.AccountBalanceQuery, + AccountLedgerQuery: tt.fields.AccountLedgerQuery, + QueryExecutor: tt.fields.QueryExecutor, + SpendableBalanceStorage: tt.fields.SpendableBalanceStorage, } if err := abh.AddAccountBalance(tt.args.address, tt.args.amount, 0, tt.args.blockHeight, 0, 0); (err != nil) != tt.wantErr { t.Errorf("AddAccountBalance() error = %v, wantErr %v", err, tt.wantErr) @@ -164,8 +174,49 @@ func (*mockAccountBalanceHelperSuccess) AddAccountBalance( ) error { return nil } +func (*mockAccountBalanceHelperSuccess) UpdateAccountSpendableBalanceInCache( + address []byte, amount int64, +) error { + return nil +} func (*mockAccountBalanceHelperFail) AddAccountBalance( address []byte, amount int64, event model.EventType, blockHeight uint32, transactionID int64, blockTimestamp uint64, ) error { return sql.ErrTxDone } + +func TestAccountBalanceHelper_AddAccountSpendableBalanceInCache(t *testing.T) { + type fields struct { + accountBalance model.AccountBalance + AccountBalanceQuery query.AccountBalanceQueryInterface + AccountLedgerQuery query.AccountLedgerQueryInterface + QueryExecutor query.ExecutorInterface + SpendableBalanceStorage storage.CacheStorageInterface + } + type args struct { + address []byte + amount int64 + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + // TODO: Add test cases. + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + abh := &AccountBalanceHelper{ + accountBalance: tt.fields.accountBalance, + AccountBalanceQuery: tt.fields.AccountBalanceQuery, + AccountLedgerQuery: tt.fields.AccountLedgerQuery, + QueryExecutor: tt.fields.QueryExecutor, + SpendableBalanceStorage: tt.fields.SpendableBalanceStorage, + } + if err := abh.AddAccountSpendableBalanceInCache(tt.args.address, tt.args.amount); (err != nil) != tt.wantErr { + t.Errorf("AccountBalanceHelper.AddAccountSpendableBalanceInCache() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/common/transaction/approvalEscrowTransaction.go b/common/transaction/approvalEscrowTransaction.go index 94f55e8ec..614af13cd 100644 --- a/common/transaction/approvalEscrowTransaction.go +++ b/common/transaction/approvalEscrowTransaction.go @@ -34,7 +34,7 @@ type ( EscrowTypeAction interface { // EscrowApplyConfirmed perhaps this method called with QueryExecutor.BeginTX() because inside this process has separated QueryExecutor.Execute EscrowApplyConfirmed(blockTimestamp int64) error - EscrowApplyUnconfirmed() error + EscrowApplyUnconfirmed(applyInCache bool) error EscrowUndoApplyUnconfirmed() error EscrowValidate(dbTx bool) error // EscrowApproval handle approval an escrow transaction, execute tasks that was skipped on EscrowApplyConfirmed. @@ -194,15 +194,24 @@ func (tx *ApprovalEscrowTransaction) checkEscrowValidity(dbTx bool, blockHeight /* ApplyUnconfirmed exec before Confirmed */ -func (tx *ApprovalEscrowTransaction) ApplyUnconfirmed() error { - return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -tx.Fee) +func (tx *ApprovalEscrowTransaction) ApplyUnconfirmed(applyInCache bool) error { + var addedSpendable = -tx.Fee + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) + } + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } /* UndoApplyUnconfirmed func exec before confirmed */ func (tx *ApprovalEscrowTransaction) UndoApplyUnconfirmed() error { - return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee) + var addedSpendable = tx.Fee + if err := tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable); err != nil { + return err + } + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } /* @@ -304,7 +313,7 @@ func (tx *ApprovalEscrowTransaction) EscrowValidate(dbTx bool) error { EscrowApplyUnconfirmed is applyUnconfirmed specific for Escrow's transaction similar with ApplyUnconfirmed and Escrow.Commission */ -func (tx *ApprovalEscrowTransaction) EscrowApplyUnconfirmed() error { +func (tx *ApprovalEscrowTransaction) EscrowApplyUnconfirmed(applyInCache bool) error { return nil } diff --git a/common/transaction/approvalEscrowTransaction_test.go b/common/transaction/approvalEscrowTransaction_test.go index 2a5ea5120..056f1da56 100644 --- a/common/transaction/approvalEscrowTransaction_test.go +++ b/common/transaction/approvalEscrowTransaction_test.go @@ -372,9 +372,13 @@ func TestApprovalEscrowTransaction_ApplyUnconfirmed(t *testing.T) { TypeActionSwitcher TypeActionSwitcher AccountBalanceHelper AccountBalanceHelperInterface } + type args struct { + applyInCache bool + } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -408,7 +412,7 @@ func TestApprovalEscrowTransaction_ApplyUnconfirmed(t *testing.T) { TypeActionSwitcher: tt.fields.TypeActionSwitcher, AccountBalanceHelper: tt.fields.AccountBalanceHelper, } - if err := tx.ApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.ApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("ApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -425,6 +429,12 @@ func (*mockAccountBalanceHelperApprovalEscrowTransactionUndoApplyUnconfirmedSucc return nil } +func (*mockAccountBalanceHelperApprovalEscrowTransactionUndoApplyUnconfirmedSuccess) UpdateAccountSpendableBalanceInCache( + address []byte, amount int64, +) error { + return nil +} + func TestApprovalEscrowTransaction_UndoApplyUnconfirmed(t *testing.T) { type fields struct { ID int64 diff --git a/common/transaction/empty.go b/common/transaction/empty.go index fe4783d1e..642e9711f 100644 --- a/common/transaction/empty.go +++ b/common/transaction/empty.go @@ -24,7 +24,7 @@ func (tx *TXEmpty) SkipMempoolTransaction( func (tx *TXEmpty) ApplyConfirmed(int64) error { return nil } -func (tx *TXEmpty) ApplyUnconfirmed() error { +func (tx *TXEmpty) ApplyUnconfirmed(applyInCache bool) error { return nil } diff --git a/common/transaction/feeVoteCommit.go b/common/transaction/feeVoteCommit.go index 68ae33bdf..91fe42a04 100644 --- a/common/transaction/feeVoteCommit.go +++ b/common/transaction/feeVoteCommit.go @@ -65,15 +65,12 @@ func (tx *FeeVoteCommitTransaction) ApplyConfirmed(blockTimestamp int64) error { } // ApplyUnconfirmed to apply unconfirmed transaction FeeVoteCommitTransaction type -func (tx *FeeVoteCommitTransaction) ApplyUnconfirmed() error { - var ( - // update account sender spendable balance - err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -tx.Fee) - ) - if err != nil { - return err +func (tx *FeeVoteCommitTransaction) ApplyUnconfirmed(applyInCache bool) error { + var addedSpendable = -tx.Fee + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } /* @@ -86,9 +83,10 @@ func (tx *FeeVoteCommitTransaction) UndoApplyUnconfirmed() error { err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee) ) if err != nil { - return blocker.NewBlocker(blocker.DBErr, err.Error()) + return err } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, tx.Fee) } /* @@ -313,12 +311,24 @@ func (tx *FeeVoteCommitTransaction) EscrowApplyConfirmed(blockTimestamp int64) ( return nil } -func (tx *FeeVoteCommitTransaction) EscrowApplyUnconfirmed() (err error) { - return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee + tx.Escrow.GetCommission())) +func (tx *FeeVoteCommitTransaction) EscrowApplyUnconfirmed(applyInCache bool) (err error) { + var addedSpendable = -(tx.Fee + tx.Escrow.GetCommission()) + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) + } + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } func (tx *FeeVoteCommitTransaction) EscrowUndoApplyUnconfirmed() error { - return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee+tx.Escrow.GetCommission()) + var ( + addedSpendable = tx.Fee + tx.Escrow.GetCommission() + err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) + ) + if err != nil { + return err + } + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } func (tx *FeeVoteCommitTransaction) EscrowValidate(dbTx bool) (err error) { diff --git a/common/transaction/feeVoteCommit_test.go b/common/transaction/feeVoteCommit_test.go index e2c8a00f1..df13c0d4e 100644 --- a/common/transaction/feeVoteCommit_test.go +++ b/common/transaction/feeVoteCommit_test.go @@ -168,18 +168,25 @@ func TestFeeVoteCommitTransaction_ApplyUnconfirmed(t *testing.T) { Fee int64 SenderAddress []byte Height uint32 - Timestamp int64 Body *model.FeeVoteCommitTransactionBody + Escrow *model.Escrow FeeScaleService fee.FeeScaleServiceInterface NodeRegistrationQuery query.NodeRegistrationQueryInterface BlockQuery query.BlockQueryInterface FeeVoteCommitmentVoteQuery query.FeeVoteCommitmentVoteQueryInterface AccountBalanceHelper AccountBalanceHelperInterface QueryExecutor query.ExecutorInterface + EscrowQuery query.EscrowTransactionQueryInterface + EscrowFee fee.FeeModelInterface + NormalFee fee.FeeModelInterface + } + type args struct { + applyInCache bool } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -223,14 +230,18 @@ func TestFeeVoteCommitTransaction_ApplyUnconfirmed(t *testing.T) { SenderAddress: tt.fields.SenderAddress, Height: tt.fields.Height, Body: tt.fields.Body, + Escrow: tt.fields.Escrow, FeeScaleService: tt.fields.FeeScaleService, NodeRegistrationQuery: tt.fields.NodeRegistrationQuery, BlockQuery: tt.fields.BlockQuery, FeeVoteCommitmentVoteQuery: tt.fields.FeeVoteCommitmentVoteQuery, AccountBalanceHelper: tt.fields.AccountBalanceHelper, QueryExecutor: tt.fields.QueryExecutor, + EscrowQuery: tt.fields.EscrowQuery, + EscrowFee: tt.fields.EscrowFee, + NormalFee: tt.fields.NormalFee, } - if err := tx.ApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.ApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("FeeVoteCommitTransaction.ApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -253,6 +264,12 @@ func (*mockAccountBalanceHelperUndoApplyUnconfirmedSuccess) AddAccountSpendableB return nil } +func (*mockAccountBalanceHelperUndoApplyUnconfirmedSuccess) UpdateAccountSpendableBalanceInCache( + address []byte, amount int64, +) error { + return nil +} + func TestFeeVoteCommitTransaction_UndoApplyUnconfirmed(t *testing.T) { type fields struct { ID int64 diff --git a/common/transaction/feeVoteReveal.go b/common/transaction/feeVoteReveal.go index 33733c304..c562e7b99 100644 --- a/common/transaction/feeVoteReveal.go +++ b/common/transaction/feeVoteReveal.go @@ -4,9 +4,10 @@ import ( "bytes" "crypto/sha256" "database/sql" - "github.com/zoobc/zoobc-core/common/crypto" "strings" + "github.com/zoobc/zoobc-core/common/crypto" + "github.com/zoobc/zoobc-core/common/blocker" "github.com/zoobc/zoobc-core/common/constant" "github.com/zoobc/zoobc-core/common/fee" @@ -180,8 +181,12 @@ func (tx *FeeVoteRevealTransaction) checkDuplicateVoteReveal(dbTx bool) error { } // ApplyUnconfirmed to apply unconfirmed transaction -func (tx *FeeVoteRevealTransaction) ApplyUnconfirmed() error { - return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -tx.Fee) +func (tx *FeeVoteRevealTransaction) ApplyUnconfirmed(applyInCache bool) error { + var addedSpendable = -tx.Fee + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) + } + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } /* @@ -189,7 +194,11 @@ UndoApplyUnconfirmed is used to undo the previous applied unconfirmed tx action this will be called on apply confirmed or when rollback occurred */ func (tx *FeeVoteRevealTransaction) UndoApplyUnconfirmed() error { - return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee) + if err := tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee); err != nil { + return err + } + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, tx.Fee) } // ApplyConfirmed applying transaction, will store ledger, account balance update, and also the transaction it self @@ -385,12 +394,24 @@ func (tx *FeeVoteRevealTransaction) EscrowApplyConfirmed(blockTimestamp int64) ( return nil } -func (tx *FeeVoteRevealTransaction) EscrowApplyUnconfirmed() (err error) { - return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -tx.Fee) +func (tx *FeeVoteRevealTransaction) EscrowApplyUnconfirmed(applyInCache bool) (err error) { + var addedSpendable = -(tx.Fee + tx.Escrow.GetCommission()) + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) + } + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } func (tx *FeeVoteRevealTransaction) EscrowUndoApplyUnconfirmed() error { - return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee) + var ( + addedSpendable = tx.Fee + tx.Escrow.GetCommission() + err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) + ) + if err != nil { + return err + } + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } func (tx *FeeVoteRevealTransaction) EscrowValidate(dbTx bool) (err error) { diff --git a/common/transaction/feeVoteReveal_test.go b/common/transaction/feeVoteReveal_test.go index 5f63880db..ec07ce271 100644 --- a/common/transaction/feeVoteReveal_test.go +++ b/common/transaction/feeVoteReveal_test.go @@ -4,7 +4,6 @@ import ( "crypto/sha256" "database/sql" "errors" - "github.com/zoobc/zoobc-core/common/crypto" "reflect" "regexp" "strings" @@ -12,6 +11,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/zoobc/zoobc-core/common/chaintype" + "github.com/zoobc/zoobc-core/common/crypto" "github.com/zoobc/zoobc-core/common/fee" "github.com/zoobc/zoobc-core/common/model" "github.com/zoobc/zoobc-core/common/query" @@ -398,6 +398,11 @@ func (*mockAccountBalanceHelperFeeVoteRevealSuccess) AddAccountSpendableBalance( func (*mockAccountBalanceHelperFeeVoteRevealSuccess) AddAccountBalance([]byte, int64, model.EventType, uint32, int64, uint64) error { return nil } +func (*mockAccountBalanceHelperFeeVoteRevealSuccess) UpdateAccountSpendableBalanceInCache( + address []byte, amount int64, +) error { + return nil +} func (*mockQueryExecutorFeeVoteRevealApplyConfirmedSuccess) ExecuteTransaction(string, ...interface{}) error { return nil @@ -420,9 +425,13 @@ func TestFeeVoteRevealTransaction_ApplyUnconfirmed(t *testing.T) { AccountBalanceHelper AccountBalanceHelperInterface QueryExecutor query.ExecutorInterface } + type args struct { + applyInCache bool + } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -450,7 +459,7 @@ func TestFeeVoteRevealTransaction_ApplyUnconfirmed(t *testing.T) { AccountBalanceHelper: tt.fields.AccountBalanceHelper, QueryExecutor: tt.fields.QueryExecutor, } - if err := tx.ApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.ApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("ApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/common/transaction/liquidPayment.go b/common/transaction/liquidPayment.go index c1ad8ebd8..8c22c87d7 100644 --- a/common/transaction/liquidPayment.go +++ b/common/transaction/liquidPayment.go @@ -72,22 +72,23 @@ func (tx *LiquidPaymentTransaction) ApplyConfirmed(blockTimestamp int64) (err er return nil } -func (tx *LiquidPaymentTransaction) ApplyUnconfirmed() (err error) { +func (tx *LiquidPaymentTransaction) ApplyUnconfirmed(applyInCache bool) (err error) { + var addedSpendable = -(tx.Body.Amount + tx.Fee) // update sender - err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Body.Amount + tx.Fee)) - if err != nil { - return err + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } func (tx *LiquidPaymentTransaction) UndoApplyUnconfirmed() (err error) { // update sender - err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Body.Amount+tx.Fee) + var addedSpendable = tx.Body.Amount + tx.Fee + err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) if err != nil { return err } - return nil + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } func (tx *LiquidPaymentTransaction) Validate(dbTx bool) error { @@ -274,26 +275,23 @@ func (tx *LiquidPaymentTransaction) EscrowApplyConfirmed(blockTimestamp int64) ( return nil } -func (tx *LiquidPaymentTransaction) EscrowApplyUnconfirmed() (err error) { - err = tx.AccountBalanceHelper.AddAccountSpendableBalance( - tx.SenderAddress, - -(tx.Body.Amount + tx.Fee + tx.Escrow.GetCommission()), - ) - if err != nil { - return err +func (tx *LiquidPaymentTransaction) EscrowApplyUnconfirmed(applyInCache bool) (err error) { + var addedSpendable = -(tx.Body.Amount + tx.Fee + tx.Escrow.GetCommission()) + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) + } func (tx *LiquidPaymentTransaction) EscrowUndoApplyUnconfirmed() (err error) { - err = tx.AccountBalanceHelper.AddAccountSpendableBalance( - tx.SenderAddress, - tx.Body.Amount+tx.Fee+tx.Escrow.GetCommission(), - ) + var addedSpendable = tx.Body.Amount + tx.Fee + tx.Escrow.GetCommission() + err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) if err != nil { return err } - return nil + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) + } func (tx *LiquidPaymentTransaction) EscrowValidate(dbTx bool) (err error) { diff --git a/common/transaction/liquidPaymentStop.go b/common/transaction/liquidPaymentStop.go index 90dc1d6a5..48b3bb597 100644 --- a/common/transaction/liquidPaymentStop.go +++ b/common/transaction/liquidPaymentStop.go @@ -107,12 +107,11 @@ func (tx *LiquidPaymentStopTransaction) ApplyConfirmed(blockTimestamp int64) err return nil } -func (tx *LiquidPaymentStopTransaction) ApplyUnconfirmed() error { - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee)) - if err != nil { - return err +func (tx *LiquidPaymentStopTransaction) ApplyUnconfirmed(applyInCache bool) error { + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, -(tx.Fee)) } - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee)) } func (tx *LiquidPaymentStopTransaction) UndoApplyUnconfirmed() error { @@ -120,7 +119,8 @@ func (tx *LiquidPaymentStopTransaction) UndoApplyUnconfirmed() error { if err != nil { return err } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, tx.Fee) } func (tx *LiquidPaymentStopTransaction) Validate(dbTx bool) error { @@ -264,23 +264,25 @@ func (tx *LiquidPaymentStopTransaction) EscrowApplyConfirmed(blockTimestamp int6 return nil } -func (tx *LiquidPaymentStopTransaction) EscrowApplyUnconfirmed() error { - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance( - tx.SenderAddress, - -(tx.Fee + tx.Escrow.GetCommission()), - ) - if err != nil { - return err +func (tx *LiquidPaymentStopTransaction) EscrowApplyUnconfirmed(applyInCache bool) error { + var addedSpendable = -(tx.Fee + tx.Escrow.GetCommission()) + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) + } func (tx *LiquidPaymentStopTransaction) EscrowUndoApplyUnconfirmed() error { - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee+tx.Escrow.GetCommission()) + var ( + addedSpendable = tx.Fee + tx.Escrow.GetCommission() + err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) + ) if err != nil { return err } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } func (tx *LiquidPaymentStopTransaction) EscrowValidate(dbTx bool) (err error) { diff --git a/common/transaction/liquidPaymentStop_test.go b/common/transaction/liquidPaymentStop_test.go index 9835defe0..9c9afa6dd 100644 --- a/common/transaction/liquidPaymentStop_test.go +++ b/common/transaction/liquidPaymentStop_test.go @@ -53,6 +53,12 @@ type ( isError bool LiquidPaymentTransaction } + mockAccountBalanceHelperLiquidPaymentStopSuccess struct { + AccountBalanceHelper + } + mockAccountBalanceHelperLiquidPaymentStopFail struct { + AccountBalanceHelper + } ) var ( @@ -142,6 +148,31 @@ func (m *mockLiquidPaymentTransaction) CompletePayment(blockHeight uint32, block return nil } +func (*mockAccountBalanceHelperLiquidPaymentStopSuccess) AddAccountSpendableBalance(address []byte, amount int64) error { + return nil +} +func (*mockAccountBalanceHelperLiquidPaymentStopSuccess) AddAccountBalance([]byte, int64, model.EventType, uint32, int64, uint64) error { + return nil +} + +func (*mockAccountBalanceHelperLiquidPaymentStopSuccess) UpdateAccountSpendableBalanceInCache( + address []byte, amount int64, +) error { + return nil +} + +func (*mockAccountBalanceHelperLiquidPaymentStopFail) AddAccountSpendableBalance(address []byte, amount int64) error { + return errors.New("mockedError") +} +func (*mockAccountBalanceHelperLiquidPaymentStopFail) AddAccountBalance([]byte, int64, model.EventType, uint32, int64, uint64) error { + return nil +} + +func (*mockAccountBalanceHelperLiquidPaymentStopFail) UpdateAccountSpendableBalanceInCache( + address []byte, amount int64, +) error { + return errors.New("mockedError") +} func TestLiquidPaymentStop_ApplyConfirmed(t *testing.T) { type fields struct { ID int64 @@ -173,6 +204,7 @@ func TestLiquidPaymentStop_ApplyConfirmed(t *testing.T) { &executorSetupLiquidPaymentStopFail{}, query.NewAccountBalanceQuery(), query.NewAccountLedgerQuery(), + nil, ), QueryExecutor: &executorSetupLiquidPaymentStopFail{}, }, @@ -181,11 +213,7 @@ func TestLiquidPaymentStop_ApplyConfirmed(t *testing.T) { { name: "wantErr:ExecuteSelectRow_error_GetPendingLiquidPaymentTransactionByID", fields: fields{ - AccountBalanceHelper: NewAccountBalanceHelper( - &executorLiquidPaymentStopApplyConfirmed{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), QueryExecutor: &executorLiquidPaymentStopApplyConfirmed{}, Body: &model.LiquidPaymentStopTransactionBody{ @@ -197,11 +225,7 @@ func TestLiquidPaymentStop_ApplyConfirmed(t *testing.T) { { name: "wantErr:Scan_error_LiquidPaymentTransactionQuery", fields: fields{ - AccountBalanceHelper: NewAccountBalanceHelper( - &executorLiquidPaymentStopApplyConfirmed{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, LiquidPaymentTransactionQuery: &mockLiquidPaymentTransactionQueryFail{}, QueryExecutor: &executorLiquidPaymentStopApplyConfirmed{}, Body: &model.LiquidPaymentStopTransactionBody{ @@ -213,11 +237,7 @@ func TestLiquidPaymentStop_ApplyConfirmed(t *testing.T) { { name: "wantErr:ExecuteSelectRow_error_GetTransaction", fields: fields{ - AccountBalanceHelper: NewAccountBalanceHelper( - &executorLiquidPaymentStopApplyConfirmed{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, LiquidPaymentTransactionQuery: &mockLiquidPaymentTransactionQuerySuccess{}, TransactionQuery: query.NewTransactionQuery(&chaintype.MainChain{}), QueryExecutor: &executorLiquidPaymentStopApplyConfirmed{}, @@ -230,11 +250,7 @@ func TestLiquidPaymentStop_ApplyConfirmed(t *testing.T) { { name: "wantErr:Scan_error_GetTransaction", fields: fields{ - AccountBalanceHelper: NewAccountBalanceHelper( - &executorLiquidPaymentStopApplyConfirmed{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, LiquidPaymentTransactionQuery: &mockLiquidPaymentTransactionQuerySuccess{}, TransactionQuery: &mockTransactionQueryFail{}, QueryExecutor: &executorLiquidPaymentStopApplyConfirmed{}, @@ -247,11 +263,7 @@ func TestLiquidPaymentStop_ApplyConfirmed(t *testing.T) { { name: "wantErr:GetTransactionType_error", fields: fields{ - AccountBalanceHelper: NewAccountBalanceHelper( - &executorLiquidPaymentStopApplyConfirmed{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, LiquidPaymentTransactionQuery: &mockLiquidPaymentTransactionQuerySuccess{}, TransactionQuery: &mockTransactionQuerySuccess{}, QueryExecutor: &executorLiquidPaymentStopApplyConfirmed{}, @@ -267,11 +279,7 @@ func TestLiquidPaymentStop_ApplyConfirmed(t *testing.T) { { name: "wantErr:casting_error_liquidPaymentTransaction", fields: fields{ - AccountBalanceHelper: NewAccountBalanceHelper( - &executorLiquidPaymentStopApplyConfirmed{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, LiquidPaymentTransactionQuery: &mockLiquidPaymentTransactionQuerySuccess{}, TransactionQuery: &mockTransactionQuerySuccess{}, QueryExecutor: &executorLiquidPaymentStopApplyConfirmed{}, @@ -287,11 +295,7 @@ func TestLiquidPaymentStop_ApplyConfirmed(t *testing.T) { { name: "wantErr:CompletePayment_error", fields: fields{ - AccountBalanceHelper: NewAccountBalanceHelper( - &executorLiquidPaymentStopApplyConfirmed{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, LiquidPaymentTransactionQuery: &mockLiquidPaymentTransactionQuerySuccess{}, TransactionQuery: &mockTransactionQuerySuccess{}, QueryExecutor: &executorLiquidPaymentStopApplyConfirmed{}, @@ -309,11 +313,7 @@ func TestLiquidPaymentStop_ApplyConfirmed(t *testing.T) { { name: "wantSuccess:status_is_already_completed", fields: fields{ - AccountBalanceHelper: NewAccountBalanceHelper( - &executorLiquidPaymentStopApplyConfirmed{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, LiquidPaymentTransactionQuery: &mockLiquidPaymentTransactionQuerySuccess{ Status: model.LiquidPaymentStatus_LiquidPaymentCompleted, }, @@ -326,11 +326,7 @@ func TestLiquidPaymentStop_ApplyConfirmed(t *testing.T) { { name: "wantSuccess", fields: fields{ - AccountBalanceHelper: NewAccountBalanceHelper( - &executorLiquidPaymentStopApplyConfirmed{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, LiquidPaymentTransactionQuery: &mockLiquidPaymentTransactionQuerySuccess{}, TransactionQuery: &mockTransactionQuerySuccess{}, QueryExecutor: &executorLiquidPaymentStopApplyConfirmed{}, @@ -383,9 +379,13 @@ func TestLiquidPaymentStop_ApplyUnconfirmed(t *testing.T) { NormalFee fee.FeeModelInterface TypeActionSwitcher TypeActionSwitcher } + type args struct { + applyInCache bool + } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -401,12 +401,8 @@ func TestLiquidPaymentStop_ApplyUnconfirmed(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentStopFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentStopFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopFail{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -423,12 +419,8 @@ func TestLiquidPaymentStop_ApplyUnconfirmed(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentStopSuccess{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentStopSuccess{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: false, }, @@ -449,7 +441,7 @@ func TestLiquidPaymentStop_ApplyUnconfirmed(t *testing.T) { NormalFee: tt.fields.NormalFee, TypeActionSwitcher: tt.fields.TypeActionSwitcher, } - if err := tx.ApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.ApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("LiquidPaymentStop.ApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -489,12 +481,8 @@ func TestLiquidPaymentStop_UndoApplyUnconfirmed(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentStopFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentStopFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopFail{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -511,12 +499,8 @@ func TestLiquidPaymentStop_UndoApplyUnconfirmed(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentStopSuccess{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentStopSuccess{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: false, }, @@ -604,12 +588,8 @@ func TestLiquidPaymentStop_Validate(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentStopFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentStopFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -625,12 +605,8 @@ func TestLiquidPaymentStop_Validate(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentStopFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentStopFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -646,12 +622,8 @@ func TestLiquidPaymentStop_Validate(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentStopFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentStopFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -667,12 +639,8 @@ func TestLiquidPaymentStop_Validate(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentStopFail{}, LiquidPaymentTransactionQuery: &mockLiquidPaymentTransactionQueryFail{}, - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentStopFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -691,12 +659,8 @@ func TestLiquidPaymentStop_Validate(t *testing.T) { Sender: liquidPayStopAddress1, Recipient: liquidPayStopAddress2, }, - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentStopSuccess{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -715,12 +679,8 @@ func TestLiquidPaymentStop_Validate(t *testing.T) { Sender: liquidPayStopAddress1, Status: model.LiquidPaymentStatus_LiquidPaymentCompleted, }, - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentStopSuccess{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentStopSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, diff --git a/common/transaction/liquidPayment_test.go b/common/transaction/liquidPayment_test.go index 2ac741074..2969b8d14 100644 --- a/common/transaction/liquidPayment_test.go +++ b/common/transaction/liquidPayment_test.go @@ -19,6 +19,12 @@ type ( executorSetupLiquidPaymentFail struct { query.Executor } + mockAccountBalanceHelperLiquidPaymentSuccess struct { + AccountBalanceHelper + } + mockAccountBalanceHelperLiquidPaymentFail struct { + AccountBalanceHelper + } ) var ( @@ -52,6 +58,37 @@ func (*executorSetupLiquidPaymentFail) ExecuteSelectRow(query string, tx bool, a return &sql.Row{}, errors.New("executor mock error") } +func (*mockAccountBalanceHelperLiquidPaymentSuccess) AddAccountSpendableBalance(address []byte, amount int64) error { + return nil +} +func (*mockAccountBalanceHelperLiquidPaymentSuccess) AddAccountBalance([]byte, int64, model.EventType, uint32, int64, uint64) error { + return nil +} +func (*mockAccountBalanceHelperLiquidPaymentSuccess) UpdateAccountSpendableBalanceInCache( + address []byte, amount int64, +) error { + return nil +} + +func (*mockAccountBalanceHelperLiquidPaymentSuccess) HasEnoughSpendableBalance( + dbTX bool, address []byte, compareBalance int64, +) (enough bool, err error) { + return true, nil +} + +func (*mockAccountBalanceHelperLiquidPaymentFail) AddAccountSpendableBalance(address []byte, amount int64) error { + return errors.New("executor mock error") +} +func (*mockAccountBalanceHelperLiquidPaymentFail) AddAccountBalance([]byte, int64, model.EventType, uint32, int64, uint64) error { + return errors.New("executor mock error") +} + +func (*mockAccountBalanceHelperLiquidPaymentFail) HasEnoughSpendableBalance( + dbTX bool, address []byte, compareBalance int64, +) (enough bool, err error) { + return false, errors.New("mockedErrror") +} + func TestLiquidPayment_ApplyConfirmed(t *testing.T) { type fields struct { ID int64 @@ -88,12 +125,8 @@ func TestLiquidPayment_ApplyConfirmed(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentFail{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, args: args{}, wantErr: true, @@ -112,12 +145,8 @@ func TestLiquidPayment_ApplyConfirmed(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentSuccess{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentSuccess{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, args: args{}, wantErr: false, @@ -157,9 +186,13 @@ func TestLiquidPayment_ApplyUnconfirmed(t *testing.T) { AccountBalanceHelper AccountBalanceHelperInterface NormalFee fee.FeeModelInterface } + type args struct { + applyInCache bool + } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -176,12 +209,8 @@ func TestLiquidPayment_ApplyUnconfirmed(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentFail{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -199,12 +228,8 @@ func TestLiquidPayment_ApplyUnconfirmed(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentSuccess{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentSuccess{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: false, }, @@ -223,7 +248,7 @@ func TestLiquidPayment_ApplyUnconfirmed(t *testing.T) { AccountBalanceHelper: tt.fields.AccountBalanceHelper, NormalFee: tt.fields.NormalFee, } - if err := tx.ApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.ApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("LiquidPayment.ApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -262,12 +287,8 @@ func TestLiquidPayment_UndoApplyUnconfirmed(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentFail{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -285,12 +306,8 @@ func TestLiquidPayment_UndoApplyUnconfirmed(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentSuccess{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentSuccess{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: false, }, @@ -371,12 +388,8 @@ func TestLiquidPayment_Validate(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentFail{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -394,12 +407,8 @@ func TestLiquidPayment_Validate(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -417,12 +426,8 @@ func TestLiquidPayment_Validate(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentFail{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -440,12 +445,8 @@ func TestLiquidPayment_Validate(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -463,12 +464,8 @@ func TestLiquidPayment_Validate(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentFail{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -486,12 +483,8 @@ func TestLiquidPayment_Validate(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentFail{}, - &mockAccountBalanceQueryForLiquidPaymentFail{}, - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentFail{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -509,10 +502,8 @@ func TestLiquidPayment_Validate(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentSuccess{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper(&executorSetupLiquidPaymentSuccess{}, &mockAccountBalanceQueryForLiquidPaymentSuccess{ - mockSpendableBalance: 1, - }, query.NewAccountLedgerQuery()), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentFail{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -530,10 +521,8 @@ func TestLiquidPayment_Validate(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentSuccess{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper(&executorSetupLiquidPaymentSuccess{}, &mockAccountBalanceQueryForLiquidPaymentSuccess{ - mockSpendableBalance: 20, - }, query.NewAccountLedgerQuery()), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: false, }, @@ -639,6 +628,7 @@ func TestLiquidPayment_GetAmount(t *testing.T) { Body: &model.LiquidPaymentTransactionBody{ Amount: 10, }, + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentSuccess{}, }, want: 10, }, @@ -654,12 +644,8 @@ func TestLiquidPayment_GetAmount(t *testing.T) { Body: tt.fields.Body, QueryExecutor: tt.fields.QueryExecutor, LiquidPaymentTransactionQuery: tt.fields.LiquidPaymentTransactionQuery, - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: tt.fields.NormalFee, + AccountBalanceHelper: tt.fields.AccountBalanceHelper, + NormalFee: tt.fields.NormalFee, } if got := tx.GetAmount(); got != tt.want { t.Errorf("LiquidPayment.GetAmount() = %v, want %v", got, tt.want) @@ -946,12 +932,8 @@ func TestLiquidPayment_CompletePayment(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentFail{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentFail{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentFail{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: true, }, @@ -973,12 +955,8 @@ func TestLiquidPayment_CompletePayment(t *testing.T) { }, QueryExecutor: &executorSetupLiquidPaymentSuccess{}, LiquidPaymentTransactionQuery: query.NewLiquidPaymentTransactionQuery(), - AccountBalanceHelper: NewAccountBalanceHelper( - &executorSetupLiquidPaymentSuccess{}, - query.NewAccountBalanceQuery(), - query.NewAccountLedgerQuery(), - ), - NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), + AccountBalanceHelper: &mockAccountBalanceHelperLiquidPaymentSuccess{}, + NormalFee: fee.NewBlockLifeTimeFeeModel(1, 2), }, wantErr: false, }, diff --git a/common/transaction/multiSignature.go b/common/transaction/multiSignature.go index 6a1647e96..c2f6ecab1 100644 --- a/common/transaction/multiSignature.go +++ b/common/transaction/multiSignature.go @@ -80,7 +80,7 @@ type ( GetPendingTransactionBySenderAddress( senderAddress []byte, txHeight uint32, ) ([]*model.PendingTransaction, error) - ApplyUnconfirmedPendingTransaction(pendingTransactionBytes []byte) error + ApplyUnconfirmedPendingTransaction(pendingTransactionBytes []byte, applyInCahc bool) error UndoApplyUnconfirmedPendingTransaction(pendingTransactionBytes []byte) error ApplyConfirmedPendingTransaction( pendingTransaction []byte, txHeight uint32, blockTimestamp int64, @@ -163,7 +163,7 @@ func (pth *PendingTransactionHelper) InsertPendingTransaction( } func (pth *PendingTransactionHelper) ApplyUnconfirmedPendingTransaction( - pendingTransactionBytes []byte, + pendingTransactionBytes []byte, applyInCache bool, ) error { // parse and apply unconfirmed innerTx, err := pth.TransactionUtil.ParseTransactionBytes(pendingTransactionBytes, false) @@ -180,7 +180,7 @@ func (pth *PendingTransactionHelper) ApplyUnconfirmedPendingTransaction( "FailToCastInnerTransaction", ) } - err = innerTa.ApplyUnconfirmed() + err = innerTa.ApplyUnconfirmed(applyInCache) if err != nil { return blocker.NewBlocker( blocker.ValidationErr, @@ -366,7 +366,7 @@ func (tx *MultiSignatureTransaction) ApplyConfirmed(blockTimestamp int64) error }, tx.Height, true) if err == sql.ErrNoRows { // apply-unconfirmed on pending transaction - err = tx.PendingTransactionHelper.ApplyUnconfirmedPendingTransaction(tx.Body.UnsignedTransactionBytes) + err = tx.PendingTransactionHelper.ApplyUnconfirmedPendingTransaction(tx.Body.UnsignedTransactionBytes, false) if err != nil { return err } @@ -475,19 +475,23 @@ func (tx *MultiSignatureTransaction) ApplyConfirmed(blockTimestamp int64) error return nil } -func (tx *MultiSignatureTransaction) ApplyUnconfirmed() error { +func (tx *MultiSignatureTransaction) ApplyUnconfirmed(applyInCache bool) error { var ( err error ) // reduce fee from sender - err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -tx.Fee) + if applyInCache { + err = tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, -tx.Fee) + } else { + err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -tx.Fee) + } if err != nil { return err } // Run ApplyUnconfirmed of inner transaction if len(tx.Body.UnsignedTransactionBytes) > 0 { // parse and apply unconfirmed - err = tx.PendingTransactionHelper.ApplyUnconfirmedPendingTransaction(tx.Body.UnsignedTransactionBytes) + err = tx.PendingTransactionHelper.ApplyUnconfirmedPendingTransaction(tx.Body.UnsignedTransactionBytes, applyInCache) if err != nil { return err } @@ -507,7 +511,9 @@ func (tx *MultiSignatureTransaction) UndoApplyUnconfirmed() error { return err } } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, tx.Fee) + } // Validate dbTx specify whether validation should read from transaction state or db state @@ -830,12 +836,20 @@ func (tx *MultiSignatureTransaction) EscrowApplyConfirmed(blockTimestamp int64) ) } -func (tx *MultiSignatureTransaction) EscrowApplyUnconfirmed() error { +func (tx *MultiSignatureTransaction) EscrowApplyUnconfirmed(applyInCache bool) error { + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, -tx.Fee) + } return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -tx.Fee) } func (tx *MultiSignatureTransaction) EscrowUndoApplyUnconfirmed() error { - return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee) + var addedSpendable = tx.Fee + tx.Escrow.GetCommission() + if err := tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable); err != nil { + return err + } + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } func (tx *MultiSignatureTransaction) EscrowValidate(dbTx bool) error { diff --git a/common/transaction/multiSignature_test.go b/common/transaction/multiSignature_test.go index da335056d..22e937b22 100644 --- a/common/transaction/multiSignature_test.go +++ b/common/transaction/multiSignature_test.go @@ -3,10 +3,11 @@ package transaction import ( "database/sql" "errors" - "github.com/zoobc/zoobc-core/common/crypto" "reflect" "testing" + "github.com/zoobc/zoobc-core/common/crypto" + "github.com/DATA-DOG/go-sqlmock" "github.com/zoobc/zoobc-core/common/fee" "github.com/zoobc/zoobc-core/common/model" @@ -849,10 +850,10 @@ func (*pendingTransactionhelperApplyUnconfirmedPendingTransactionTypeSwitcherSuc return &pendingTransactionhelperApplyUnconfirmedPendingTransactionActionTypeSuccess{}, nil } -func (*pendingTransactionhelperApplyUnconfirmedPendingTransactionActionTypeSuccess) ApplyUnconfirmed() error { +func (*pendingTransactionhelperApplyUnconfirmedPendingTransactionActionTypeSuccess) ApplyUnconfirmed(bool) error { return nil } -func (*pendingTransactionhelperApplyUnconfirmedPendingTransactionActionTypeFail) ApplyUnconfirmed() error { +func (*pendingTransactionhelperApplyUnconfirmedPendingTransactionActionTypeFail) ApplyUnconfirmed(bool) error { return errors.New("mockedError") } @@ -866,6 +867,7 @@ func TestPendingTransactionHelper_ApplyUnconfirmedPendingTransaction(t *testing. } type args struct { pendingTransactionBytes []byte + applyInCache bool } tests := []struct { name string @@ -926,7 +928,7 @@ func TestPendingTransactionHelper_ApplyUnconfirmedPendingTransaction(t *testing. TypeSwitcher: tt.fields.TypeSwitcher, QueryExecutor: tt.fields.QueryExecutor, } - if err := pth.ApplyUnconfirmedPendingTransaction(tt.args.pendingTransactionBytes); (err != nil) != tt.wantErr { + if err := pth.ApplyUnconfirmedPendingTransaction(tt.args.pendingTransactionBytes, tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("ApplyUnconfirmedPendingTransaction() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -1587,6 +1589,11 @@ func (*mockAccountBalanceHelperAddAccountSpendableBalanceSuccess) AddAccountSpen address []byte, amount int64) error { return nil } +func (*mockAccountBalanceHelperAddAccountSpendableBalanceSuccess) UpdateAccountSpendableBalanceInCache( + address []byte, amount int64, +) error { + return nil +} func (*mockUndoApplyUnconfirmedPendingTransactionHelperUndoPendingFail) UndoApplyUnconfirmedPendingTransaction( pendingTransactionBytes []byte) error { @@ -1699,12 +1706,14 @@ type ( ) func (*mockApplyUnconfirmedPendingTransactionHelperApplyUnconfirmedFail) ApplyUnconfirmedPendingTransaction( - pendingTransactionBytes []byte) error { + pendingTransactionBytes []byte, applyInCache bool, +) error { return errors.New("mockedError") } func (*mockApplyUnconfirmedPendingTransactionHelperApplyUnconfirmedSuccess) ApplyUnconfirmedPendingTransaction( - pendingTransactionBytes []byte) error { + pendingTransactionBytes []byte, applyInCache bool, +) error { return nil } @@ -1727,9 +1736,13 @@ func TestMultiSignatureTransaction_ApplyUnconfirmed(t *testing.T) { AccountBalanceHelper AccountBalanceHelperInterface TransactionHelper TransactionHelperInterface } + type args struct { + applyInCache bool + } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -1792,7 +1805,7 @@ func TestMultiSignatureTransaction_ApplyUnconfirmed(t *testing.T) { AccountBalanceHelper: tt.fields.AccountBalanceHelper, TransactionHelper: tt.fields.TransactionHelper, } - if err := tx.ApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.ApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("ApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/common/transaction/nodeRegistration.go b/common/transaction/nodeRegistration.go index 076dfdee6..c9a1236a1 100644 --- a/common/transaction/nodeRegistration.go +++ b/common/transaction/nodeRegistration.go @@ -4,8 +4,8 @@ import ( "bytes" "database/sql" "errors" - "github.com/zoobc/zoobc-core/common/accounttype" + "github.com/zoobc/zoobc-core/common/accounttype" "github.com/zoobc/zoobc-core/common/auth" "github.com/zoobc/zoobc-core/common/blocker" "github.com/zoobc/zoobc-core/common/constant" @@ -182,23 +182,26 @@ func (tx *NodeRegistration) ApplyConfirmed(blockTimestamp int64) error { ApplyUnconfirmed is func that for applying to unconfirmed Transaction `NodeRegistration` type: - perhaps recipient is not exists , so create new `account` and `account_balance`, balance and spendable = amount. */ -func (tx *NodeRegistration) ApplyUnconfirmed() error { +func (tx *NodeRegistration) ApplyUnconfirmed(applyInCache bool) error { + var addedSpendable = -(tx.Body.GetLockedBalance() + tx.Fee) // update sender balance by reducing his spendable balance of the tx fee - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Body.GetLockedBalance() + tx.Fee)) - if err != nil { - return err + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } - - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } func (tx *NodeRegistration) UndoApplyUnconfirmed() error { // update sender balance by reducing his spendable balance of the tx fee - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Body.GetLockedBalance()+tx.Fee) + var ( + addedSpendable = tx.Body.GetLockedBalance() + tx.Fee + err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) + ) if err != nil { return err } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } // Validate validate node registration transaction and tx body @@ -437,15 +440,12 @@ func (tx *NodeRegistration) EscrowValidate(dbTx bool) error { // EscrowApplyUnconfirmed is applyUnconfirmed specific for Escrow's transaction // similar with ApplyUnconfirmed and Escrow.Commission -func (tx *NodeRegistration) EscrowApplyUnconfirmed() error { - - // update sender balance by reducing his spendable balance of the tx fee - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Body.GetLockedBalance() + tx.Fee + tx.Escrow.GetCommission())) - if err != nil { - return err +func (tx *NodeRegistration) EscrowApplyUnconfirmed(applyInCache bool) error { + var addedSpendable = -(tx.Body.GetLockedBalance() + tx.Fee + tx.Escrow.GetCommission()) + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } - - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } // EscrowUndoApplyUnconfirmed is used to undo the previous applied unconfirmed tx action @@ -453,12 +453,15 @@ func (tx *NodeRegistration) EscrowApplyUnconfirmed() error { func (tx *NodeRegistration) EscrowUndoApplyUnconfirmed() error { // update sender balance by reducing his spendable balance of the tx fee - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Body.GetLockedBalance()+tx.Fee+tx.Escrow.GetCommission()) + var ( + addedSpendable = tx.Body.GetLockedBalance() + tx.Fee + tx.Escrow.GetCommission() + err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) + ) if err != nil { return err } - - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } // EscrowApplyConfirmed func that for applying Transaction SendMoney type diff --git a/common/transaction/nodeRegistrationClaim.go b/common/transaction/nodeRegistrationClaim.go index 335758e65..4d72ede3e 100644 --- a/common/transaction/nodeRegistrationClaim.go +++ b/common/transaction/nodeRegistrationClaim.go @@ -3,8 +3,8 @@ package transaction import ( "bytes" "database/sql" - "github.com/zoobc/zoobc-core/common/accounttype" + "github.com/zoobc/zoobc-core/common/accounttype" "github.com/zoobc/zoobc-core/common/auth" "github.com/zoobc/zoobc-core/common/blocker" "github.com/zoobc/zoobc-core/common/constant" @@ -139,14 +139,11 @@ func (tx *ClaimNodeRegistration) ApplyConfirmed(blockTimestamp int64) error { ApplyUnconfirmed is func that for applying to unconfirmed Transaction `ClaimNodeRegistration` type: - perhaps recipient is not exists , so create new `account` and `account_balance`, balance and spendable = amount. */ -func (tx *ClaimNodeRegistration) ApplyUnconfirmed() error { - - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee)) - if err != nil { - return err +func (tx *ClaimNodeRegistration) ApplyUnconfirmed(applyInCache bool) error { + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, -(tx.Fee)) } - - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee)) } func (tx *ClaimNodeRegistration) UndoApplyUnconfirmed() error { @@ -155,7 +152,8 @@ func (tx *ClaimNodeRegistration) UndoApplyUnconfirmed() error { if err != nil { return err } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, tx.Fee) } // Validate validate node registration transaction and tx body @@ -330,13 +328,12 @@ func (tx *ClaimNodeRegistration) EscrowValidate(dbTX bool) error { EscrowApplyUnconfirmed is func that for applying to unconfirmed Transaction `ClaimNodeRegistration` type: - perhaps recipient is not exists , so create new `account` and `account_balance`, balance and spendable = amount. */ -func (tx *ClaimNodeRegistration) EscrowApplyUnconfirmed() error { - - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee + tx.Escrow.GetCommission())) - if err != nil { - return err +func (tx *ClaimNodeRegistration) EscrowApplyUnconfirmed(applyInCache bool) error { + var addedSpendable = -(tx.Fee + tx.Escrow.GetCommission()) + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } /* @@ -344,11 +341,15 @@ EscrowUndoApplyUnconfirmed func that perform on apply confirm preparation */ func (tx *ClaimNodeRegistration) EscrowUndoApplyUnconfirmed() error { - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee+tx.Escrow.GetCommission()) + var ( + addedSpendable = tx.Fee + tx.Escrow.GetCommission() + err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) + ) if err != nil { return err } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } /* diff --git a/common/transaction/nodeRegistrationClaim_test.go b/common/transaction/nodeRegistrationClaim_test.go index bf0c83a86..76f06470a 100644 --- a/common/transaction/nodeRegistrationClaim_test.go +++ b/common/transaction/nodeRegistrationClaim_test.go @@ -471,9 +471,13 @@ func TestClaimNodeRegistration_ApplyUnconfirmed(t *testing.T) { AuthPoown auth.NodeAuthValidationInterface AccountBalanceHelper AccountBalanceHelperInterface } + type args struct { + applyInCache bool + } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -503,7 +507,7 @@ func TestClaimNodeRegistration_ApplyUnconfirmed(t *testing.T) { AuthPoown: tt.fields.AuthPoown, AccountBalanceHelper: tt.fields.AccountBalanceHelper, } - if err := tx.ApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.ApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("ClaimNodeRegistration.ApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -525,6 +529,11 @@ func (*mockAccountBalanceHelperClaimNRUndoApplyUnconfirmedFail) AddAccountSpenda func (*mockAccountBalanceHelperClaimNRUndoApplyUnconfirmedSuccess) AddAccountSpendableBalance(address []byte, amount int64) error { return nil } +func (*mockAccountBalanceHelperClaimNRUndoApplyUnconfirmedSuccess) UpdateAccountSpendableBalanceInCache( + address []byte, amount int64, +) error { + return nil +} func TestClaimNodeRegistration_UndoApplyUnconfirmed(t *testing.T) { _, txBody, _ := GetFixturesForClaimNoderegistration() type fields struct { diff --git a/common/transaction/nodeRegistrationUpdate.go b/common/transaction/nodeRegistrationUpdate.go index 6d3c6e68e..d577fa79b 100644 --- a/common/transaction/nodeRegistrationUpdate.go +++ b/common/transaction/nodeRegistrationUpdate.go @@ -3,8 +3,8 @@ package transaction import ( "bytes" "database/sql" - "github.com/zoobc/zoobc-core/common/accounttype" + "github.com/zoobc/zoobc-core/common/accounttype" "github.com/zoobc/zoobc-core/common/auth" "github.com/zoobc/zoobc-core/common/blocker" "github.com/zoobc/zoobc-core/common/constant" @@ -153,7 +153,7 @@ func (tx *UpdateNodeRegistration) ApplyConfirmed(blockTimestamp int64) error { ApplyUnconfirmed is func that for applying to unconfirmed Transaction `UpdateNodeRegistration` type: - perhaps recipient is not exists , so create new `account` and `account_balance`, balance and spendable = amount. */ -func (tx *UpdateNodeRegistration) ApplyUnconfirmed() error { +func (tx *UpdateNodeRegistration) ApplyUnconfirmed(applyInCache bool) error { var ( effectiveBalanceToLock int64 @@ -179,20 +179,18 @@ func (tx *UpdateNodeRegistration) ApplyUnconfirmed() error { // delta amount to be locked effectiveBalanceToLock = tx.Body.GetLockedBalance() - nodeReg.GetLockedBalance() } - - err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(effectiveBalanceToLock + tx.Fee)) - if err != nil { - return err + var addedSpendable = -(effectiveBalanceToLock + tx.Fee) + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } func (tx *UpdateNodeRegistration) UndoApplyUnconfirmed() error { var ( - err error - effectiveBalanceToLock int64 - prevNodeRegistration model.NodeRegistration - row *sql.Row + err error + prevNodeRegistration model.NodeRegistration + row *sql.Row ) // get the latest nodeRegistration by owner (sender account) qry, args := tx.NodeRegistrationQuery.GetNodeRegistrationByAccountAddress(tx.SenderAddress) @@ -209,13 +207,17 @@ func (tx *UpdateNodeRegistration) UndoApplyUnconfirmed() error { } // delta amount to be locked - effectiveBalanceToLock = tx.Body.LockedBalance - prevNodeRegistration.LockedBalance + var ( + effectiveBalanceToLock = tx.Body.LockedBalance - prevNodeRegistration.LockedBalance + addedSpendable = effectiveBalanceToLock + tx.Fee + ) // update sender balance by reducing his spendable balance of the tx fee - err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, effectiveBalanceToLock+tx.Fee) + err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) if err != nil { return err } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } // Validate validate node registration transaction and tx body @@ -459,7 +461,7 @@ func (tx *UpdateNodeRegistration) EscrowValidate(dbTx bool) error { EscrowApplyUnconfirmed is func that for applying to unconfirmed Transaction `UpdateNodeRegistration` type, perhaps recipient is not exists , so create new `account` and `account_balance`, balance and spendable = amount. */ -func (tx *UpdateNodeRegistration) EscrowApplyUnconfirmed() error { +func (tx *UpdateNodeRegistration) EscrowApplyUnconfirmed(applyInCache bool) error { var ( effectiveBalanceToLock int64 @@ -489,12 +491,11 @@ func (tx *UpdateNodeRegistration) EscrowApplyUnconfirmed() error { // delta amount to be locked effectiveBalanceToLock = tx.Body.GetLockedBalance() - nodeRegistration.GetLockedBalance() } - - err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(effectiveBalanceToLock + tx.Fee + tx.Escrow.GetCommission())) - if err != nil { - return err + var addedSpendable = -(effectiveBalanceToLock + tx.Fee + tx.Escrow.GetCommission()) + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } /* @@ -502,10 +503,9 @@ EscrowUndoApplyUnconfirmed func that perform on apply confirm preparation */ func (tx *UpdateNodeRegistration) EscrowUndoApplyUnconfirmed() error { var ( - effectiveBalanceToLock int64 - nodeRegistration model.NodeRegistration - row *sql.Row - err error + nodeRegistration model.NodeRegistration + row *sql.Row + err error ) // get the latest node registration by owner (sender account) @@ -524,13 +524,17 @@ func (tx *UpdateNodeRegistration) EscrowUndoApplyUnconfirmed() error { } // delta amount to be locked - effectiveBalanceToLock = tx.Body.GetLockedBalance() - nodeRegistration.GetLockedBalance() + var ( + effectiveBalanceToLock = tx.Body.GetLockedBalance() - nodeRegistration.GetLockedBalance() + addedSpendable = effectiveBalanceToLock + tx.Fee + tx.Escrow.GetCommission() + ) - err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, effectiveBalanceToLock+tx.Fee+tx.Escrow.GetCommission()) + err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) if err != nil { return err } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } // EscrowApplyConfirmed method for confirmed the transaction and store into database diff --git a/common/transaction/nodeRegistrationUpdate_test.go b/common/transaction/nodeRegistrationUpdate_test.go index 74097bad0..0e01dadb0 100644 --- a/common/transaction/nodeRegistrationUpdate_test.go +++ b/common/transaction/nodeRegistrationUpdate_test.go @@ -552,9 +552,13 @@ func TestUpdateNodeRegistration_ApplyUnconfirmed(t *testing.T) { AuthPoown auth.NodeAuthValidationInterface AccountBalanceHelper AccountBalanceHelperInterface } + type args struct { + applyInCache bool + } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -594,7 +598,7 @@ func TestUpdateNodeRegistration_ApplyUnconfirmed(t *testing.T) { AuthPoown: tt.fields.AuthPoown, AccountBalanceHelper: tt.fields.AccountBalanceHelper, } - if err := tx.ApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.ApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("UpdateNodeRegistration.ApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -749,10 +753,20 @@ type ( func (*mockAccountBalanceHelperUpdateNRUndoApplyUnconfirmedSuccess) AddAccountSpendableBalance(address []byte, amount int64) error { return nil } +func (*mockAccountBalanceHelperUpdateNRUndoApplyUnconfirmedSuccess) UpdateAccountSpendableBalanceInCache( + address []byte, amount int64, +) error { + return nil +} + func (*mockAccountBalanceHelperUpdateNRUndoApplyUnconfirmedFail) AddAccountSpendableBalance(address []byte, amount int64) error { return sql.ErrNoRows } - +func (*mockAccountBalanceHelperUpdateNRUndoApplyUnconfirmedFail) UpdateAccountSpendableBalanceInCache( + address []byte, amount int64, +) error { + return nil +} func TestUpdateNodeRegistration_UndoApplyUnconfirmed(t *testing.T) { txBody := &model.UpdateNodeRegistrationTransactionBody{ LockedBalance: int64(10000000000), diff --git a/common/transaction/nodeRegistration_test.go b/common/transaction/nodeRegistration_test.go index a2a68f06b..bfa2db23b 100644 --- a/common/transaction/nodeRegistration_test.go +++ b/common/transaction/nodeRegistration_test.go @@ -911,9 +911,15 @@ func (*mockAccountBalanceHelperNRSuccess) HasEnoughSpendableBalance( ) (enough bool, err error) { return true, nil } +func (*mockAccountBalanceHelperNRSuccess) UpdateAccountSpendableBalanceInCache( + address []byte, amount int64, +) error { + return nil +} func (*mockAccountBalanceHelperNRFail) AddAccountSpendableBalance(address []byte, amount int64) error { return sql.ErrTxDone } + func (*mockAccountBalanceHelperNRFail) HasEnoughSpendableBalance( dbTX bool, address []byte, compareBalance int64, ) (enough bool, err error) { @@ -931,9 +937,13 @@ func TestNodeRegistration_ApplyUnconfirmed(t *testing.T) { QueryExecutor query.ExecutorInterface AccountBalanceHelper AccountBalanceHelperInterface } + type args struct { + applyInCache bool + } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -981,7 +991,7 @@ func TestNodeRegistration_ApplyUnconfirmed(t *testing.T) { QueryExecutor: tt.fields.QueryExecutor, AccountBalanceHelper: tt.fields.AccountBalanceHelper, } - if err := tx.ApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.ApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("NodeRegistration.ApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/common/transaction/removeAccountDataset.go b/common/transaction/removeAccountDataset.go index 24e883e26..2225a6ab8 100644 --- a/common/transaction/removeAccountDataset.go +++ b/common/transaction/removeAccountDataset.go @@ -80,14 +80,11 @@ func (tx *RemoveAccountDataset) ApplyConfirmed(blockTimestamp int64) error { /* ApplyUnconfirmed is func that for applying to unconfirmed Transaction `RemoveAccountDataset` type */ -func (tx *RemoveAccountDataset) ApplyUnconfirmed() error { - - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee)) - if err != nil { - return blocker.NewBlocker(blocker.DBErr, err.Error()) +func (tx *RemoveAccountDataset) ApplyUnconfirmed(applyInCache bool) error { + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, -(tx.Fee)) } - - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee)) } /* @@ -95,13 +92,11 @@ UndoApplyUnconfirmed is used to undo the previous applied unconfirmed tx action this will be called on apply confirmed or when rollback occurred */ func (tx *RemoveAccountDataset) UndoApplyUnconfirmed() error { - - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee) - if err != nil { - return blocker.NewBlocker(blocker.DBErr, err.Error()) + if err := tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee); err != nil { + return err } - - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, tx.Fee) } /* @@ -310,14 +305,12 @@ func (tx *RemoveAccountDataset) EscrowValidate(dbTx bool) error { /* EscrowApplyUnconfirmed is func that for applying to unconfirmed Transaction `RemoveAccountDataset` type */ -func (tx *RemoveAccountDataset) EscrowApplyUnconfirmed() error { - - err := tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee + tx.Escrow.GetCommission())) - if err != nil { - return err +func (tx *RemoveAccountDataset) EscrowApplyUnconfirmed(applyInCache bool) error { + var addedSpendable = -(tx.Fee + tx.Escrow.GetCommission()) + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } - - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } /* @@ -325,13 +318,16 @@ EscrowUndoApplyUnconfirmed is used to undo the previous applied unconfirmed tx a this will be called on apply confirmed or when rollback occurred */ func (tx *RemoveAccountDataset) EscrowUndoApplyUnconfirmed() error { - - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee+tx.Escrow.GetCommission()) + var ( + addedSpendable = tx.Fee + tx.Escrow.GetCommission() + err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) + ) if err != nil { return err } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } /* diff --git a/common/transaction/removeAccountDataset_test.go b/common/transaction/removeAccountDataset_test.go index bbdf7bb64..8006d0fba 100644 --- a/common/transaction/removeAccountDataset_test.go +++ b/common/transaction/removeAccountDataset_test.go @@ -185,9 +185,13 @@ func TestRemoveAccountDataset_ApplyUnconfirmed(t *testing.T) { QueryExecutor query.ExecutorInterface AccountBalanceHelper AccountBalanceHelperInterface } + type args struct { + applyInCache bool + } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -237,7 +241,7 @@ func TestRemoveAccountDataset_ApplyUnconfirmed(t *testing.T) { QueryExecutor: tt.fields.QueryExecutor, AccountBalanceHelper: tt.fields.AccountBalanceHelper, } - if err := tx.ApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.ApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("RemoveAccountDataset.ApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/common/transaction/removeNodeRegistration.go b/common/transaction/removeNodeRegistration.go index 0b379e0bb..84bc336aa 100644 --- a/common/transaction/removeNodeRegistration.go +++ b/common/transaction/removeNodeRegistration.go @@ -150,23 +150,21 @@ func (tx *RemoveNodeRegistration) ApplyConfirmed(blockTimestamp int64) error { ApplyUnconfirmed is func that for applying to unconfirmed Transaction `RemoveNodeRegistration` type: - perhaps recipient is not exists , so create new `account` and `account_balance`, balance and spendable = amount. */ -func (tx *RemoveNodeRegistration) ApplyUnconfirmed() error { - - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee)) - if err != nil { - return err +func (tx *RemoveNodeRegistration) ApplyUnconfirmed(applyInCache bool) error { + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, -(tx.Fee)) } - - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee)) } func (tx *RemoveNodeRegistration) UndoApplyUnconfirmed() error { - - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee) - if err != nil { + var addedSpendable = tx.Fee + if err := tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable); err != nil { return err } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) + } // Validate validate node registration transaction and tx body @@ -316,27 +314,26 @@ func (tx *RemoveNodeRegistration) EscrowValidate(dbTx bool) error { EscrowApplyUnconfirmed is func that for applying to unconfirmed Transaction `RemoveNodeRegistration` type. Perhaps recipient is not exists , so create new `account` and `account_balance`, balance and spendable = amount. */ -func (tx *RemoveNodeRegistration) EscrowApplyUnconfirmed() error { - +func (tx *RemoveNodeRegistration) EscrowApplyUnconfirmed(applyInCache bool) error { // update sender balance by reducing his spendable balance of the tx fee - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee + tx.Escrow.GetCommission())) - if err != nil { - return err + var addedSpendable = -(tx.Fee + tx.Escrow.GetCommission()) + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } - - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } /* EscrowUndoApplyUnconfirmed func that perform on apply confirm preparation */ func (tx *RemoveNodeRegistration) EscrowUndoApplyUnconfirmed() error { - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee+tx.Escrow.GetCommission()) - if err != nil { + var addedSpendable = tx.Fee + tx.Escrow.GetCommission() + if err := tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable); err != nil { return err } + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) - return nil } // EscrowApplyConfirmed method for confirmed the transaction and store into database diff --git a/common/transaction/removeNodeRegistration_test.go b/common/transaction/removeNodeRegistration_test.go index 6c133d1af..68323e097 100644 --- a/common/transaction/removeNodeRegistration_test.go +++ b/common/transaction/removeNodeRegistration_test.go @@ -546,9 +546,13 @@ func TestRemoveNodeRegistration_ApplyUnconfirmed(t *testing.T) { QueryExecutor query.ExecutorInterface AccountBalanceHelper AccountBalanceHelperInterface } + type args struct { + applyInCache bool + } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -587,7 +591,7 @@ func TestRemoveNodeRegistration_ApplyUnconfirmed(t *testing.T) { QueryExecutor: tt.fields.QueryExecutor, AccountBalanceHelper: tt.fields.AccountBalanceHelper, } - if err := tx.ApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.ApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("RemoveNodeRegistration.ApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/common/transaction/sendMoney.go b/common/transaction/sendMoney.go index c03b21326..5b0c07676 100644 --- a/common/transaction/sendMoney.go +++ b/common/transaction/sendMoney.go @@ -84,13 +84,12 @@ func (tx *SendMoney) ApplyConfirmed(blockTimestamp int64) error { ApplyUnconfirmed is func that for applying to unconfirmed Transaction `SendMoney` type: - perhaps recipient is not exists , so create new `account` and `account_balance`, balance and spendable = amount. */ -func (tx *SendMoney) ApplyUnconfirmed() error { - - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Body.GetAmount() + tx.Fee)) - if err != nil { - return err +func (tx *SendMoney) ApplyUnconfirmed(applyInCache bool) error { + var addedSpendable = -(tx.Body.GetAmount() + tx.Fee) + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } /* @@ -98,11 +97,12 @@ UndoApplyUnconfirmed is used to undo the previous applied unconfirmed tx action this will be called on apply confirmed or when rollback occurred */ func (tx *SendMoney) UndoApplyUnconfirmed() error { - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Body.GetAmount()+tx.Fee) - if err != nil { + var addedSpendable = tx.Body.GetAmount() + tx.Fee + if err := tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable); err != nil { return err } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } /* @@ -265,14 +265,12 @@ func (tx *SendMoney) EscrowValidate(dbTx bool) error { EscrowApplyUnconfirmed is applyUnconfirmed specific for Escrow's transaction similar with ApplyUnconfirmed and Escrow.Commission */ -func (tx *SendMoney) EscrowApplyUnconfirmed() error { - - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Body.GetAmount() + tx.Fee + tx.Escrow.GetCommission())) - if err != nil { - return err +func (tx *SendMoney) EscrowApplyUnconfirmed(applyInCache bool) error { + var addedSpendable = -(tx.Body.GetAmount() + tx.Fee + tx.Escrow.GetCommission()) + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } - return nil - + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable) } /* @@ -280,12 +278,13 @@ EscrowUndoApplyUnconfirmed is used to undo the previous applied unconfirmed tx a this will be called on apply confirmed or when rollback occurred */ func (tx *SendMoney) EscrowUndoApplyUnconfirmed() error { - - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Body.GetAmount()+tx.Escrow.GetCommission()+tx.Fee) - if err != nil { + var addedSpendable = tx.Body.GetAmount() + tx.Escrow.GetCommission() + tx.Fee + if err := tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable); err != nil { return err } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) + } /* diff --git a/common/transaction/sendMoney_test.go b/common/transaction/sendMoney_test.go index c7239d3e5..c38408cf5 100644 --- a/common/transaction/sendMoney_test.go +++ b/common/transaction/sendMoney_test.go @@ -264,9 +264,13 @@ func TestSendMoney_ApplyUnconfirmed(t *testing.T) { QueryExecutor query.ExecutorInterface AccountBalanceHelper AccountBalanceHelperInterface } + type args struct { + applyInCache bool + } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -312,7 +316,7 @@ func TestSendMoney_ApplyUnconfirmed(t *testing.T) { QueryExecutor: tt.fields.QueryExecutor, AccountBalanceHelper: tt.fields.AccountBalanceHelper, } - if err := tx.ApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.ApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("SendMoney.ApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } if err := mock.ExpectationsWereMet(); err != nil { @@ -1017,9 +1021,13 @@ func TestSendMoney_EscrowApplyUnconfirmed(t *testing.T) { BlockQuery query.BlockQueryInterface AccountBalanceHelper AccountBalanceHelperInterface } + type args struct { + applyInCache bool + } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -1060,7 +1068,7 @@ func TestSendMoney_EscrowApplyUnconfirmed(t *testing.T) { BlockQuery: tt.fields.BlockQuery, AccountBalanceHelper: tt.fields.AccountBalanceHelper, } - if err := tx.EscrowApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.EscrowApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("EscrowApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/common/transaction/setupAccountDataset.go b/common/transaction/setupAccountDataset.go index 72425690d..c5bf1cbeb 100644 --- a/common/transaction/setupAccountDataset.go +++ b/common/transaction/setupAccountDataset.go @@ -80,13 +80,11 @@ func (tx *SetupAccountDataset) ApplyConfirmed(blockTimestamp int64) error { /* ApplyUnconfirmed is func that for applying to unconfirmed Transaction `SetupAccountDataset` type */ -func (tx *SetupAccountDataset) ApplyUnconfirmed() error { - - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee)) - if err != nil { - return blocker.NewBlocker(blocker.DBErr, err.Error()) +func (tx *SetupAccountDataset) ApplyUnconfirmed(applyInCache bool) error { + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache(tx.SenderAddress, -(tx.Fee)) } - return nil + return tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, -(tx.Fee)) } /* @@ -94,12 +92,12 @@ UndoApplyUnconfirmed is used to undo the previous applied unconfirmed tx action this will be called on apply confirmed or when rollback occurred */ func (tx *SetupAccountDataset) UndoApplyUnconfirmed() error { - - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee) - if err != nil { + var addedSpendable = tx.Fee + if err := tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable); err != nil { return blocker.NewBlocker(blocker.DBErr, err.Error()) } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } /* @@ -305,16 +303,18 @@ func (tx *SetupAccountDataset) EscrowValidate(dbTx bool) error { /* EscrowApplyUnconfirmed is func that for applying to unconfirmed Transaction `SetupAccountDataset` type. */ -func (tx *SetupAccountDataset) EscrowApplyUnconfirmed() error { - - var err = tx.AccountBalanceHelper.AddAccountSpendableBalance( +func (tx *SetupAccountDataset) EscrowApplyUnconfirmed(applyInCache bool) error { + var addedSpendable = -(tx.Fee + tx.Escrow.GetCommission()) + if applyInCache { + return tx.AccountBalanceHelper.AddAccountSpendableBalanceInCache( + tx.SenderAddress, + addedSpendable, + ) + } + return tx.AccountBalanceHelper.AddAccountSpendableBalance( tx.SenderAddress, - -(tx.Fee + tx.Escrow.GetCommission()), + addedSpendable, ) - if err != nil { - return blocker.NewBlocker(blocker.DBErr, err.Error()) - } - return nil } /* @@ -323,11 +323,12 @@ this will be called on apply confirmed or when rollback occurred */ func (tx *SetupAccountDataset) EscrowUndoApplyUnconfirmed() error { - err := tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, tx.Fee+tx.Escrow.GetCommission()) - if err != nil { + var addedSpendable = tx.Fee + tx.Escrow.GetCommission() + if err := tx.AccountBalanceHelper.AddAccountSpendableBalance(tx.SenderAddress, addedSpendable); err != nil { return blocker.NewBlocker(blocker.DBErr, err.Error()) } - return nil + // update existing spendable balance in cache storage + return tx.AccountBalanceHelper.UpdateAccountSpendableBalanceInCache(tx.SenderAddress, addedSpendable) } /* diff --git a/common/transaction/setupAccountDataset_test.go b/common/transaction/setupAccountDataset_test.go index 13cc1cfdb..442984404 100644 --- a/common/transaction/setupAccountDataset_test.go +++ b/common/transaction/setupAccountDataset_test.go @@ -172,9 +172,13 @@ func TestSetupAccountDataset_ApplyUnconfirmed(t *testing.T) { QueryExecutor query.ExecutorInterface AccountBalanceHelper AccountBalanceHelperInterface } + type args struct { + applyInCache bool + } tests := []struct { name string fields fields + args args wantErr bool }{ { @@ -222,7 +226,7 @@ func TestSetupAccountDataset_ApplyUnconfirmed(t *testing.T) { QueryExecutor: tt.fields.QueryExecutor, AccountBalanceHelper: tt.fields.AccountBalanceHelper, } - if err := tx.ApplyUnconfirmed(); (err != nil) != tt.wantErr { + if err := tx.ApplyUnconfirmed(tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("SetupAccountDataset.ApplyUnconfirmed() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/common/transaction/transaction.go b/common/transaction/transaction.go index e4475c1d3..a6b451189 100644 --- a/common/transaction/transaction.go +++ b/common/transaction/transaction.go @@ -19,7 +19,7 @@ type ( TypeAction interface { // ApplyConfirmed perhaps this method called with QueryExecutor.BeginTX() because inside this process has separated QueryExecutor.Execute ApplyConfirmed(blockTimestamp int64) error - ApplyUnconfirmed() error + ApplyUnconfirmed(applyInCache bool) error UndoApplyUnconfirmed() error // Validate dbTx specify whether validation should read from transaction state or db state Validate(dbTx bool) error @@ -49,6 +49,7 @@ type ( NodeAddressInfoStorage storage.TransactionalCache PendingNodeRegistryStorage storage.TransactionalCache ActiveNodeRegistryStorage storage.TransactionalCache + SpendabelBalanceStorage storage.CacheStorageInterface FeeScaleService fee.FeeScaleServiceInterface } ) @@ -56,15 +57,20 @@ type ( // GetTransactionType assert transaction to TypeAction func (ts *TypeSwitcher) GetTransactionType(tx *model.Transaction) (TypeAction, error) { var ( + err error buf = util.ConvertUint32ToBytes(tx.GetTransactionType()) - accountBalanceHelper = NewAccountBalanceHelper(ts.Executor, query.NewAccountBalanceQuery(), query.NewAccountLedgerQuery()) transactionHelper = NewTransactionHelper(query.NewTransactionQuery(&chaintype.MainChain{}), ts.Executor) transactionBody model.TransactionBodyInterface - transactionUtil = &Util{ + accountBalanceHelper = NewAccountBalanceHelper( + ts.Executor, + query.NewAccountBalanceQuery(), + query.NewAccountLedgerQuery(), + ts.SpendabelBalanceStorage, + ) + transactionUtil = &Util{ MempoolCacheStorage: ts.MempoolCacheStorage, FeeScaleService: ts.FeeScaleService, } - err error ) switch buf[0] { diff --git a/common/transaction/transaction_test.go b/common/transaction/transaction_test.go index 6de145fb4..db3cd1e45 100644 --- a/common/transaction/transaction_test.go +++ b/common/transaction/transaction_test.go @@ -3,13 +3,13 @@ package transaction import ( "crypto/sha256" "encoding/binary" - "github.com/zoobc/zoobc-core/common/crypto" "reflect" "testing" "github.com/zoobc/zoobc-core/common/auth" "github.com/zoobc/zoobc-core/common/chaintype" "github.com/zoobc/zoobc-core/common/constant" + "github.com/zoobc/zoobc-core/common/crypto" "github.com/zoobc/zoobc-core/common/fee" "github.com/zoobc/zoobc-core/common/model" "github.com/zoobc/zoobc-core/common/query" @@ -45,7 +45,12 @@ func TestTypeSwitcher_GetTransactionType(t *testing.T) { }, "ZOOBC") liquidPaymentBody, liquidPaymentBytes := GetFixturesForLiquidPaymentTransaction() liquidPaymentStopBody, liquidPaymentStopBytes := GetFixturesForLiquidPaymentStopTransaction() - accountBalanceHelper := NewAccountBalanceHelper(&query.Executor{}, query.NewAccountBalanceQuery(), query.NewAccountLedgerQuery()) + accountBalanceHelper := NewAccountBalanceHelper( + &query.Executor{}, + query.NewAccountBalanceQuery(), + query.NewAccountLedgerQuery(), + nil, + ) // cache mock fixtureTransactionalCache := func(cache interface{}) storage.TransactionalCache { return cache.(storage.TransactionalCache) diff --git a/core/blockchainsync/processFork.go b/core/blockchainsync/processFork.go index e5a846a7c..31b23780e 100644 --- a/core/blockchainsync/processFork.go +++ b/core/blockchainsync/processFork.go @@ -254,7 +254,7 @@ func (fp *ForkingProcessor) ProcessLater(txs []*model.Transaction) error { continue } - err = fp.TransactionCorService.ApplyUnconfirmedTransaction(txType) + err = fp.TransactionCorService.ApplyUnconfirmedTransaction(txType, false) if err != nil { fp.Logger.Warnf("ProcessLater:ApplyUnconfirmedTransaction - tx.Height: %d - txID: %d - %s", tx.GetHeight(), tx.GetID(), err.Error()) continue @@ -322,7 +322,7 @@ func (fp *ForkingProcessor) restoreMempoolsBackup() error { return } - err = fp.TransactionCorService.ApplyUnconfirmedTransaction(txType) + err = fp.TransactionCorService.ApplyUnconfirmedTransaction(txType, false) if err != nil { fp.Logger.Warnf("restoreMempoolsBackup:ApplyUnconfirmedTransaction: %v", err) return diff --git a/core/service/blockMainService.go b/core/service/blockMainService.go index 0cefadb77..4fa5b4a30 100644 --- a/core/service/blockMainService.go +++ b/core/service/blockMainService.go @@ -417,6 +417,11 @@ func (bs *BlockService) PushBlock(previousBlock, block *model.Block, broadcast, bs.queryAndCacheRollbackProcess(fmt.Sprintf("NodeAddressInfoCacheBeginTransaction - %s", err.Error())) return blocker.NewBlocker(blocker.BlockErr, err.Error()) } + err = bs.MempoolService.SpendableBalanceBeginCacheTransaction() + if err != nil { + bs.queryAndCacheRollbackProcess(fmt.Sprintf("SpendableBalanceBeginCacheTransaction - %s", err.Error())) + return blocker.NewBlocker(blocker.BlockErr, err.Error()) + } /* Expiring Process: expiring the transactions that affected by current block height. Respecting Expiring escrow and multi signature transaction before push block process @@ -754,6 +759,11 @@ func (bs *BlockService) PushBlock(previousBlock, block *model.Block, broadcast, return err } } + err = bs.MempoolService.SpendableBalanceCommitCacheTransaction() + if err != nil { + bs.queryAndCacheRollbackProcess("") + return err + } bs.Logger.Debugf("%s Block Pushed ID: %d", bs.Chaintype.GetName(), block.GetID()) // clear the block pool bs.BlockPoolService.ClearBlockPool() @@ -783,6 +793,10 @@ func (bs *BlockService) queryAndCacheRollbackProcess(rollbackErrLable string) { if err != nil { bs.Logger.Errorf("noderegistry:cacheRollbackErr - %s", err.Error()) } + err = bs.MempoolService.SpendableBalanceRollbackCacheTransaction() + if err != nil { + bs.Logger.Errorf("spendableBalance:cacheRollbackErr - %s", err.Error()) + } if rollbackErr := bs.QueryExecutor.RollbackTx(); rollbackErr != nil { bs.Logger.Errorf("%s:%s", rollbackErrLable, rollbackErr.Error()) } diff --git a/core/service/blockMainService_test.go b/core/service/blockMainService_test.go index 0fa07ebb2..4d352fabc 100644 --- a/core/service/blockMainService_test.go +++ b/core/service/blockMainService_test.go @@ -1377,20 +1377,27 @@ type ( mockMempoolCacheStorageRemoveMempoolTransactionsSuccess struct { storage.CacheStorageInterface } + mockMempoolUnsaveCacheStorageRemoveMempoolTransactionsSuccess struct { + storage.CacheStorageInterface + } ) func (*mockMempoolCacheStorageRemoveMempoolTransactionsSuccess) RemoveItem(item interface{}) error { return nil } +func (*mockMempoolUnsaveCacheStorageRemoveMempoolTransactionsSuccess) RemoveItem(item interface{}) error { + return nil +} func TestMempoolService_RemoveMempoolTransactions(t *testing.T) { type fields struct { - Chaintype chaintype.ChainType - QueryExecutor query.ExecutorInterface - MempoolQuery query.MempoolQueryInterface - Signature crypto.SignatureInterface - MempoolCacheStorage storage.CacheStorageInterface - Logger *log.Logger + Chaintype chaintype.ChainType + QueryExecutor query.ExecutorInterface + MempoolQuery query.MempoolQueryInterface + Signature crypto.SignatureInterface + MempoolCacheStorage storage.CacheStorageInterface + MempoolUnsaveCacheStorage storage.CacheStorageInterface + Logger *log.Logger } type args struct { transactions []*model.Transaction @@ -1404,11 +1411,12 @@ func TestMempoolService_RemoveMempoolTransactions(t *testing.T) { { name: "RemoveMempoolTransaction:Success", fields: fields{ - Chaintype: &chaintype.MainChain{}, - MempoolQuery: query.NewMempoolQuery(&chaintype.MainChain{}), - QueryExecutor: &mockQueryExecutorSuccess{}, - MempoolCacheStorage: &mockMempoolCacheStorageRemoveMempoolTransactionsSuccess{}, - Logger: log.New(), + Chaintype: &chaintype.MainChain{}, + MempoolQuery: query.NewMempoolQuery(&chaintype.MainChain{}), + QueryExecutor: &mockQueryExecutorSuccess{}, + MempoolCacheStorage: &mockMempoolCacheStorageRemoveMempoolTransactionsSuccess{}, + MempoolUnsaveCacheStorage: &mockMempoolUnsaveCacheStorageRemoveMempoolTransactionsSuccess{}, + Logger: log.New(), }, args: args{ transactions: []*model.Transaction{ @@ -1450,12 +1458,13 @@ func TestMempoolService_RemoveMempoolTransactions(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bs := &MempoolService{ - Chaintype: tt.fields.Chaintype, - QueryExecutor: tt.fields.QueryExecutor, - MempoolQuery: tt.fields.MempoolQuery, - Signature: tt.fields.Signature, - Logger: tt.fields.Logger, - MempoolCacheStorage: tt.fields.MempoolCacheStorage, + Chaintype: tt.fields.Chaintype, + QueryExecutor: tt.fields.QueryExecutor, + MempoolQuery: tt.fields.MempoolQuery, + Signature: tt.fields.Signature, + Logger: tt.fields.Logger, + MempoolCacheStorage: tt.fields.MempoolCacheStorage, + MempoolUnsaveCacheStorage: tt.fields.MempoolUnsaveCacheStorage, } if err := bs.RemoveMempoolTransactions(tt.args.transactions); (err != nil) != tt.wantErr { t.Errorf("BlockService.RemoveMempoolTransactions() error = %v, wantErr %v", err, tt.wantErr) @@ -1762,6 +1771,9 @@ type ( mockAddGenesisNodeAddressInfoServiceSuccess struct { NodeAddressInfoServiceInterface } + mockAddGenensisMempoolServiceSuccess struct { + MempoolService + } ) func (*mockAddGenesisNodeAddressInfoServiceSuccess) BeginCacheTransaction() error { @@ -1814,6 +1826,24 @@ func (*mockScrambleServiceAddGenesisSuccess) GetBlockHeightToBuildScrambleNodes( return 1 } +func (*mockAddGenensisMempoolServiceSuccess) SelectTransactionsFromMempool(blockTimestamp int64, blockHeight uint32) ([]*model.Transaction, error) { + return nil, nil +} + +// mockMempoolServiceSelectFail +func (*mockAddGenensisMempoolServiceSuccess) GetMempoolTransactions() (storage.MempoolMap, error) { + return make(storage.MempoolMap), nil +} +func (*mockAddGenensisMempoolServiceSuccess) SpendableBalanceBeginCacheTransaction() error { + return nil +} +func (*mockAddGenensisMempoolServiceSuccess) SpendableBalanceRollbackCacheTransaction() error { + return nil +} +func (*mockAddGenensisMempoolServiceSuccess) SpendableBalanceCommitCacheTransaction() error { + return nil +} + func TestBlockService_AddGenesis(t *testing.T) { type fields struct { Chaintype chaintype.ChainType @@ -1851,7 +1881,7 @@ func TestBlockService_AddGenesis(t *testing.T) { Signature: &mockSignature{}, MempoolQuery: query.NewMempoolQuery(&chaintype.MainChain{}), AccountBalanceQuery: query.NewAccountBalanceQuery(), - MempoolService: &mockMempoolServiceSelectFail{}, + MempoolService: &mockAddGenensisMempoolServiceSuccess{}, ActionTypeSwitcher: &mockTypeActionSuccess{}, QueryExecutor: &mockAddGenesisExecutor{}, BlockQuery: query.NewBlockQuery(&chaintype.MainChain{}), diff --git a/core/service/mempoolCoreService.go b/core/service/mempoolCoreService.go index 61f18e418..74b34ff2f 100644 --- a/core/service/mempoolCoreService.go +++ b/core/service/mempoolCoreService.go @@ -2,8 +2,10 @@ package service import ( "database/sql" + "fmt" "sort" "strconv" + "sync" "time" log "github.com/sirupsen/logrus" @@ -33,11 +35,15 @@ type ( GetTotalMempoolTransactions() (int, error) SelectTransactionsFromMempool(blockTimestamp int64, blockHeight uint32) ([]*model.Transaction, error) ValidateMempoolTransaction(mpTx *model.Transaction) error - ReceivedTransaction( + ReceivedTransactionFromP2P( senderPublicKey, receivedTxBytes []byte, lastBlockCacheFromat *storage.BlockCacheObject, nodeSecretPhrase string, ) (*model.Receipt, error) + ReceivedTransactionFromWallet( + receivedTx *model.Transaction, + receivedTxBytes []byte, + ) error ReceivedBlockTransactions( senderPublicKey []byte, receivedTxBytes [][]byte, @@ -47,27 +53,36 @@ type ( DeleteExpiredMempoolTransactions() error GetMempoolTransactionsWantToBackup(height uint32) ([]*model.Transaction, error) BackupMempools(commonBlock *model.Block) error + MoveFullCacheMempools() error + SpendableBalanceBeginCacheTransaction() error + SpendableBalanceRollbackCacheTransaction() error + SpendableBalanceCommitCacheTransaction() error } // MempoolService contains all transactions in mempool plus a mux to manage locks in concurrency MempoolService struct { - TransactionUtil transaction.UtilInterface - Chaintype chaintype.ChainType - QueryExecutor query.ExecutorInterface - MempoolQuery query.MempoolQueryInterface - MerkleTreeQuery query.MerkleTreeQueryInterface - ActionTypeSwitcher transaction.TypeActionSwitcher - AccountBalanceQuery query.AccountBalanceQueryInterface - TransactionQuery query.TransactionQueryInterface - Signature crypto.SignatureInterface - Observer *observer.Observer - Logger *log.Logger - ReceiptUtil coreUtil.ReceiptUtilInterface - ReceiptService ReceiptServiceInterface - TransactionCoreService TransactionCoreServiceInterface - BlocksStorage storage.CacheStackStorageInterface - MempoolCacheStorage storage.CacheStorageInterface - MempoolBackupStorage storage.CacheStorageInterface + TransactionUtil transaction.UtilInterface + Chaintype chaintype.ChainType + QueryExecutor query.ExecutorInterface + MempoolQuery query.MempoolQueryInterface + MerkleTreeQuery query.MerkleTreeQueryInterface + ActionTypeSwitcher transaction.TypeActionSwitcher + AccountBalanceQuery query.AccountBalanceQueryInterface + TransactionQuery query.TransactionQueryInterface + Signature crypto.SignatureInterface + Observer *observer.Observer + Logger *log.Logger + ReceiptUtil coreUtil.ReceiptUtilInterface + ReceiptService ReceiptServiceInterface + TransactionCoreService TransactionCoreServiceInterface + BlocksStorage storage.CacheStackStorageInterface + MempoolCacheStorage storage.CacheStorageInterface + MempoolBackupStorage storage.CacheStorageInterface + MempoolUnsaveCacheStorage storage.CacheStorageInterface + SpendableBalanceStorage storage.CacheStorageInterface + lastIncomingTransactionTime time.Time + accountsUnsaveMempoolIDsMap map[string]map[int64]bool + accountsUnsaveMempoolIDsMapLock sync.RWMutex } ) @@ -88,26 +103,30 @@ func NewMempoolService( receiptService ReceiptServiceInterface, transactionCoreService TransactionCoreServiceInterface, blocksStorage storage.CacheStackStorageInterface, - mempoolCacheStorage, mempoolBackupStorage storage.CacheStorageInterface, + mempoolCacheStorage, mempoolBackupStorage, + mempoolUnsaveCacheStorage, spendableBalanceStorage storage.CacheStorageInterface, ) *MempoolService { return &MempoolService{ - TransactionUtil: transactionUtil, - Chaintype: ct, - QueryExecutor: queryExecutor, - MempoolQuery: mempoolQuery, - MerkleTreeQuery: merkleTreeQuery, - ActionTypeSwitcher: actionTypeSwitcher, - AccountBalanceQuery: accountBalanceQuery, - Signature: signature, - TransactionQuery: transactionQuery, - Observer: observer, - Logger: logger, - ReceiptUtil: receiptUtil, - ReceiptService: receiptService, - TransactionCoreService: transactionCoreService, - BlocksStorage: blocksStorage, - MempoolCacheStorage: mempoolCacheStorage, - MempoolBackupStorage: mempoolBackupStorage, + TransactionUtil: transactionUtil, + Chaintype: ct, + QueryExecutor: queryExecutor, + MempoolQuery: mempoolQuery, + MerkleTreeQuery: merkleTreeQuery, + ActionTypeSwitcher: actionTypeSwitcher, + AccountBalanceQuery: accountBalanceQuery, + Signature: signature, + TransactionQuery: transactionQuery, + Observer: observer, + Logger: logger, + ReceiptUtil: receiptUtil, + ReceiptService: receiptService, + TransactionCoreService: transactionCoreService, + BlocksStorage: blocksStorage, + MempoolCacheStorage: mempoolCacheStorage, + MempoolBackupStorage: mempoolBackupStorage, + MempoolUnsaveCacheStorage: mempoolUnsaveCacheStorage, + SpendableBalanceStorage: spendableBalanceStorage, + accountsUnsaveMempoolIDsMap: make(map[string]map[int64]bool), } } @@ -155,12 +174,17 @@ func (mps *MempoolService) RemoveMempoolTransactions(transactions []*model.Trans var ( idsStr []string ids []int64 + err error ) for _, tx := range transactions { idsStr = append(idsStr, "'"+strconv.FormatInt(tx.GetID(), 10)+"'") ids = append(ids, tx.GetID()) + err = mps.removeMapMempoolSpendableBalanceCache(tx.SenderAccountAddress, tx.ID) + if err != nil { + return err + } } - err := mps.QueryExecutor.ExecuteTransaction(mps.MempoolQuery.DeleteMempoolTransactions(idsStr)) + err = mps.QueryExecutor.ExecuteTransaction(mps.MempoolQuery.DeleteMempoolTransactions(idsStr)) if err != nil { return err } @@ -168,12 +192,16 @@ func (mps *MempoolService) RemoveMempoolTransactions(transactions []*model.Trans if err != nil { return err } + err = mps.MempoolUnsaveCacheStorage.RemoveItem(ids) + if err != nil { + return err + } mps.Logger.Infof("mempool transaction with IDs = %s deleted", idsStr) return nil } func (mps *MempoolService) GetTotalMempoolTransactions() (int, error) { - return mps.MempoolCacheStorage.GetTotalItems(), nil + return mps.MempoolCacheStorage.GetTotalItems() + mps.MempoolUnsaveCacheStorage.GetTotalItems(), nil } // GetMempoolTransactions fetch transactions from mempool @@ -191,33 +219,25 @@ func (mps *MempoolService) GetMempoolTransactions() (storage.MempoolMap, error) // AddMempoolTransaction validates and insert a transaction into the mempool and also set the BlockHeight as well func (mps *MempoolService) AddMempoolTransaction(tx *model.Transaction, txBytes []byte) error { - // check maximum mempool - if constant.MaxMempoolTransactions > 0 { - var count, err = mps.GetTotalMempoolTransactions() - if err != nil { - return err - } - if count >= constant.MaxMempoolTransactions { - return blocker.NewBlocker(blocker.ValidationErr, "Mempool already full") - } + var ( + arrivalTime = time.Now() + lastBlock storage.BlockCacheObject + err = mps.BlocksStorage.GetTop(&lastBlock) + ) + if err != nil { + return err } - mpTx := &model.MempoolTransaction{ FeePerByte: commonUtils.FeePerByteTransaction(tx.GetFee(), txBytes), ID: tx.GetID(), TransactionBytes: txBytes, - ArrivalTimestamp: time.Now().Unix(), + ArrivalTimestamp: arrivalTime.UTC().Unix(), SenderAccountAddress: tx.GetSenderAccountAddress(), RecipientAccountAddress: tx.GetRecipientAccountAddress(), + BlockHeight: lastBlock.Height, } // NOTE: this select is always inside a db transaction because AddMempoolTransaction is always called within a db tx - var lastBlock storage.BlockCacheObject - err := mps.BlocksStorage.GetTop(&lastBlock) - if err != nil { - return err - } - mpTx.BlockHeight = lastBlock.Height insertMempoolQ, insertMempoolArgs := mps.MempoolQuery.InsertMempoolTransaction(mpTx) err = mps.QueryExecutor.ExecuteTransaction(insertMempoolQ, insertMempoolArgs...) if err != nil { @@ -225,7 +245,7 @@ func (mps *MempoolService) AddMempoolTransaction(tx *model.Transaction, txBytes } err = mps.MempoolCacheStorage.SetItem(tx.GetID(), storage.MempoolCacheObject{ Tx: *tx, - ArrivalTimestamp: time.Now().UTC().Unix(), + ArrivalTimestamp: arrivalTime.UTC().Unix(), FeePerByte: mpTx.FeePerByte, TransactionByteSize: uint32(len(txBytes)), BlockHeight: mpTx.BlockHeight, @@ -233,18 +253,70 @@ func (mps *MempoolService) AddMempoolTransaction(tx *model.Transaction, txBytes if err != nil { return err } + mps.lastIncomingTransactionTime = arrivalTime + return nil +} + +// AddMempoolFullCache add transaction into unsave mempool transaction +func (mps *MempoolService) AddMempoolFullCache(tx *model.Transaction, txBytes []byte) error { + var lastBlock storage.BlockCacheObject + err := mps.BlocksStorage.GetTop(&lastBlock) + if err != nil { + return err + } + + var arrivalTime = time.Now() + err = mps.MempoolUnsaveCacheStorage.SetItem(tx.GetID(), storage.MempoolCacheObject{ + Tx: *tx, + TxBytes: txBytes, + ArrivalTimestamp: arrivalTime.UTC().Unix(), + FeePerByte: commonUtils.FeePerByteTransaction(tx.GetFee(), txBytes), + TransactionByteSize: uint32(len(txBytes)), + BlockHeight: lastBlock.Height, + }) + if err != nil { + return err + } + mps.lastIncomingTransactionTime = arrivalTime + // save map of transaction unsave to track spendable cache + var accountStr = fmt.Sprintf("%q", tx.SenderAccountAddress) + mps.accountsUnsaveMempoolIDsMapLock.Lock() + defer mps.accountsUnsaveMempoolIDsMapLock.Unlock() + if mps.accountsUnsaveMempoolIDsMap[accountStr] == nil { + mps.accountsUnsaveMempoolIDsMap[accountStr] = make(map[int64]bool) + } + mps.accountsUnsaveMempoolIDsMap[accountStr][tx.ID] = true return nil } func (mps *MempoolService) ValidateMempoolTransaction(mpTx *model.Transaction) error { + // check maximum mempool + if constant.MaxMempoolTransactions > 0 { + var count, err = mps.GetTotalMempoolTransactions() + if err != nil { + return err + } + if count >= constant.MaxMempoolTransactions { + return blocker.NewBlocker(blocker.ValidationErr, "Mempool already full") + } + } var ( - mempoolObj storage.MempoolCacheObject - tx model.Transaction - err error - row *sql.Row - txType transaction.TypeAction + mempoolObj, + unsaveMempoolObj storage.MempoolCacheObject + tx model.Transaction + err error + row *sql.Row + txType transaction.TypeAction ) - // check duplication in mempool cache + // check duplication in unsave mempool cache + err = mps.MempoolUnsaveCacheStorage.GetItem(mpTx.GetID(), &unsaveMempoolObj) + if err != nil { + return blocker.NewBlocker(blocker.ValidationErr, "FailReadingMempoolCache") + } + if mpTx.GetID() == unsaveMempoolObj.Tx.GetID() { + return blocker.NewBlocker(blocker.DuplicateMempoolErr, "MempoolDuplicated") + } + // check duplication in save mempool cache err = mps.MempoolCacheStorage.GetItem(mpTx.GetID(), &mempoolObj) if err != nil { return blocker.NewBlocker(blocker.ValidationErr, "FailReadingMempoolCache") @@ -252,7 +324,6 @@ func (mps *MempoolService) ValidateMempoolTransaction(mpTx *model.Transaction) e if mpTx.GetID() == mempoolObj.Tx.GetID() { return blocker.NewBlocker(blocker.DuplicateMempoolErr, "MempoolDuplicated") } - // check for duplication in transaction table transactionQ := mps.TransactionQuery.GetTransaction(mpTx.GetID()) row, err = mps.QueryExecutor.ExecuteSelectRow(transactionQ, false) @@ -352,7 +423,7 @@ func (mps *MempoolService) SelectTransactionsFromMempool(blockTimestamp int64, b return selectedTransactions, nil } -func (mps *MempoolService) ReceivedTransaction( +func (mps *MempoolService) ReceivedTransactionFromP2P( senderPublicKey, receivedTxBytes []byte, lastBlock *storage.BlockCacheObject, nodeSecretPhrase string, @@ -362,7 +433,7 @@ func (mps *MempoolService) ReceivedTransaction( receivedTx *model.Transaction receipt *model.Receipt ) - receipt, receivedTx, err = mps.ProcessReceivedTransaction( + receipt, receivedTx, err = mps.processeReceiptAndValidateTransactionP2P( senderPublicKey, receivedTxBytes, lastBlock, @@ -375,25 +446,66 @@ func (mps *MempoolService) ReceivedTransaction( if receivedTx == nil { return receipt, nil } - err = mps.QueryExecutor.BeginTx() + err = mps.processReceiveTransaction(receivedTx, receivedTxBytes) if err != nil { - return nil, status.Error(codes.Internal, err.Error()) + return nil, err } - txType, err := mps.ActionTypeSwitcher.GetTransactionType(receivedTx) + return receipt, nil +} + +func (mps *MempoolService) ReceivedTransactionFromWallet( + receivedTx *model.Transaction, + receivedTxBytes []byte, +) error { + return mps.processReceiveTransaction(receivedTx, receivedTxBytes) +} + +func (mps *MempoolService) processReceiveTransaction(receivedTx *model.Transaction, receivedTxBytes []byte) error { + var txType, err = mps.ActionTypeSwitcher.GetTransactionType(receivedTx) if err != nil { rollbackErr := mps.QueryExecutor.RollbackTx() if rollbackErr != nil { mps.Logger.Warnf("rollbackErr:ReceivedTransaction - %v", rollbackErr) } - return nil, status.Error(codes.InvalidArgument, err.Error()) + return status.Error(codes.InvalidArgument, err.Error()) + } + var isApplyInCache bool + switch { + case mps.lastIncomingTransactionTime.IsZero(): + isApplyInCache = false + fallthrough + case time.Since(mps.lastIncomingTransactionTime).Seconds() < constant.MempoolMaxTimeGapBecameFullCacheTransaction, + mps.MempoolUnsaveCacheStorage.GetTotalItems() > 0: + // apply in unsave mempool when last incoming timestamp is lees than 1 second OR + // unsave mempool storage still have unmove transaction + isApplyInCache = true + } + // save into full cache mempool transaction (unsave mempool) + if isApplyInCache { + err = mps.TransactionCoreService.ApplyUnconfirmedTransaction(txType, isApplyInCache) + if err != nil { + return err + } + err = mps.AddMempoolFullCache(receivedTx, receivedTxBytes) + if err != nil { + return err + } + mps.Observer.Notify(observer.TransactionAdded, receivedTxBytes, mps.Chaintype) + return nil } - err = mps.TransactionCoreService.ApplyUnconfirmedTransaction(txType) + + // save into DB mempool transaction + err = mps.QueryExecutor.BeginTx() + if err != nil { + return status.Error(codes.Internal, err.Error()) + } + err = mps.TransactionCoreService.ApplyUnconfirmedTransaction(txType, false) if err != nil { mps.Logger.Infof("fail ApplyUnconfirmed tx: %v\n", err) if rollbackErr := mps.QueryExecutor.RollbackTx(); rollbackErr != nil { mps.Logger.Error(rollbackErr.Error()) } - return nil, status.Error(codes.InvalidArgument, err.Error()) + return status.Error(codes.InvalidArgument, err.Error()) } // Store to Mempool Transaction if err = mps.AddMempoolTransaction(receivedTx, receivedTxBytes); err != nil { @@ -401,20 +513,20 @@ func (mps *MempoolService) ReceivedTransaction( if rollbackErr := mps.QueryExecutor.RollbackTx(); rollbackErr != nil { mps.Logger.Error(rollbackErr.Error()) } - return nil, status.Error(codes.InvalidArgument, err.Error()) + return status.Error(codes.InvalidArgument, err.Error()) } err = mps.QueryExecutor.CommitTx() if err != nil { mps.Logger.Warnf("error committing db transaction: %v", err) - return nil, status.Error(codes.Internal, err.Error()) + return status.Error(codes.Internal, err.Error()) } mps.Observer.Notify(observer.TransactionAdded, receivedTxBytes, mps.Chaintype) - return receipt, nil + return nil } -// ProcessReceivedTransaction process the transaction received from peer +// processeReceiptAndValidateTransactionP2P process the transaction received from peer // will return batchReceipt, `nil`, `nil` if duplicate transaction found -func (mps *MempoolService) ProcessReceivedTransaction( +func (mps *MempoolService) processeReceiptAndValidateTransactionP2P( senderPublicKey, receivedTxBytes []byte, lastBlockCacheFromat *storage.BlockCacheObject, nodeSecretPhrase string, @@ -474,7 +586,7 @@ func (mps *MempoolService) ReceivedBlockTransactions( receivedTransactions []*model.Transaction ) for _, txBytes := range receivedTxBytes { - batchReceipt, receivedTx, err := mps.ProcessReceivedTransaction( + batchReceipt, receivedTx, err := mps.processeReceiptAndValidateTransactionP2P( senderPublicKey, txBytes, lastBlockCacheFromat, @@ -533,6 +645,10 @@ func (mps *MempoolService) DeleteExpiredMempoolTransactions() error { if err != nil { return err } + err = mps.SpendableBalanceBeginCacheTransaction() + if err != nil { + return err + } for _, memObj := range cachedTxs { if memObj.ArrivalTimestamp > expirationTime { continue @@ -577,6 +693,10 @@ func (mps *MempoolService) DeleteExpiredMempoolTransactions() error { if err != nil { return err } + err = mps.SpendableBalanceCommitCacheTransaction() + if err != nil { + return err + } return nil } @@ -619,6 +739,10 @@ func (mps *MempoolService) BackupMempools(commonBlock *model.Block) error { return err } + err = mps.SpendableBalanceBeginCacheTransaction() + if err != nil { + return err + } for _, mempoolTx := range mempoolsBackup { var ( txType transaction.TypeAction @@ -682,7 +806,10 @@ func (mps *MempoolService) BackupMempools(commonBlock *model.Block) error { if err != nil { return err } - + err = mps.SpendableBalanceCommitCacheTransaction() + if err != nil { + return err + } err = mps.MempoolBackupStorage.SetItems(backupMempools) if err != nil { return err @@ -690,3 +817,146 @@ func (mps *MempoolService) BackupMempools(commonBlock *model.Block) error { return nil } + +// MoveFullCacheMempools to move full cache mempool to DB mempool +func (mps *MempoolService) MoveFullCacheMempools() error { + if mps.MempoolUnsaveCacheStorage.GetTotalItems() > 0 { + var ( + err error + cachedTxs = make(storage.MempoolMap) + ) + err = mps.MempoolUnsaveCacheStorage.GetAllItems(cachedTxs) + if err != nil { + return err + } + err = mps.QueryExecutor.BeginTx() + if err != nil { + return err + } + var movedMempoolID []int64 + // start re apply unconfimed transaction + for mempoolID, memObj := range cachedTxs { + tx := memObj.Tx + txType, err := mps.ActionTypeSwitcher.GetTransactionType(&tx) + if err != nil { + if rollbackErr := mps.QueryExecutor.RollbackTx(); rollbackErr != nil { + mps.Logger.Error(rollbackErr.Error()) + } + return err + } + err = mps.TransactionCoreService.ApplyUnconfirmedTransaction(txType, false) + if err != nil { + mps.Logger.Infof("fail ApplyUnconfirmed tx: %v\n", err) + if rollbackErr := mps.QueryExecutor.RollbackTx(); rollbackErr != nil { + mps.Logger.Error(rollbackErr.Error()) + } + return err + } + // Store to Mempool Transaction + insertMempoolQ, insertMempoolArgs := mps.MempoolQuery.InsertMempoolTransaction( + &model.MempoolTransaction{ + ID: tx.GetID(), + SenderAccountAddress: tx.GetSenderAccountAddress(), + RecipientAccountAddress: tx.GetRecipientAccountAddress(), + FeePerByte: memObj.FeePerByte, + TransactionBytes: memObj.TxBytes, + ArrivalTimestamp: memObj.ArrivalTimestamp, + BlockHeight: memObj.BlockHeight, + }, + ) + err = mps.QueryExecutor.ExecuteTransaction(insertMempoolQ, insertMempoolArgs...) + if err != nil { + if rollbackErr := mps.QueryExecutor.RollbackTx(); rollbackErr != nil { + mps.Logger.Errorf("rollbackErr:MoveMempool - %v", rollbackErr) + } + return err + } + // make sure the order add & remove between save & usnave mempool cache + // is same with order of check duplicate on ValidateMempool to avoid duplicated mempol when moving mempool + // save into normal mempool cache + err = mps.MempoolCacheStorage.SetItem(tx.GetID(), memObj) + if err != nil { + if rollbackErr := mps.QueryExecutor.RollbackTx(); rollbackErr != nil { + mps.Logger.Error(rollbackErr.Error()) + } + return err + } + // remove mempool that already move from full cache (unsave mempool) to normal mempool + err = mps.MempoolUnsaveCacheStorage.RemoveItem(mempoolID) + if err != nil { + if rollbackErr := mps.QueryExecutor.RollbackTx(); rollbackErr != nil { + mps.Logger.Error(rollbackErr.Error()) + } + return err + } + err = mps.removeMapMempoolSpendableBalanceCache(tx.SenderAccountAddress, tx.ID) + if err != nil { + if rollbackErr := mps.QueryExecutor.RollbackTx(); rollbackErr != nil { + mps.Logger.Error(rollbackErr.Error()) + } + return err + } + movedMempoolID = append(movedMempoolID, mempoolID) + // stop moving mempool if already reach maximum move + if len(movedMempoolID) == constant.MempoolMaxMoveTrasactions { + break + } + } + err = mps.QueryExecutor.CommitTx() + if err != nil { + mps.Logger.Warnf("error committing db transaction: %v", err) + return err + } + + } + return nil +} + +func (mps *MempoolService) removeMapMempoolSpendableBalanceCache(senderAccountAddress []byte, txID int64) error { + // delete mapping accout address with mempool ID & cahce spendabel balance if neded + var accountStr = fmt.Sprintf("%q", senderAccountAddress) + mps.accountsUnsaveMempoolIDsMapLock.Lock() + defer mps.accountsUnsaveMempoolIDsMapLock.Unlock() + if mps.accountsUnsaveMempoolIDsMap[accountStr] != nil { + delete(mps.accountsUnsaveMempoolIDsMap[accountStr], txID) + if len(mps.accountsUnsaveMempoolIDsMap[accountStr]) == 0 { + var err = mps.SpendableBalanceStorage.RemoveItem(senderAccountAddress) + if err != nil { + return err + } + delete(mps.accountsUnsaveMempoolIDsMap, accountStr) + } + } + return nil +} + +// SpendableBalanceBeginCacheTransaction start transactional process for spendable balance storage +func (mps *MempoolService) SpendableBalanceBeginCacheTransaction() error { + txSpendableBalanceCache, ok := mps.SpendableBalanceStorage.(storage.TransactionalCache) + if !ok { + return blocker.NewBlocker(blocker.AppErr, "FailToCastSpendableBalanceStorageAsTransactionalCacheInterface") + } + return txSpendableBalanceCache.Begin() +} + +// SpendableBalanceBeginCacheTransaction revert all transactional process for spendable balance storage +func (mps *MempoolService) SpendableBalanceRollbackCacheTransaction() error { + txSpendableBalanceCache, ok := mps.SpendableBalanceStorage.(storage.TransactionalCache) + if !ok { + return blocker.NewBlocker(blocker.AppErr, "FailToCastSpendableBalanceStorageAsTransactionalCacheInterface") + } + return txSpendableBalanceCache.Rollback() +} + +// SpendableBalanceBeginCacheTransaction saved all transactional into main spendable balance cache +func (mps *MempoolService) SpendableBalanceCommitCacheTransaction() error { + txSpendableBalanceCache, ok := mps.SpendableBalanceStorage.(storage.TransactionalCache) + if !ok { + return blocker.NewBlocker(blocker.AppErr, "FailToCastSpendableBalanceStorageAsTransactionalCacheInterface") + } + return txSpendableBalanceCache.Commit() +} + +func (mps *MempoolService) TestStorage() storage.CacheStorageInterface { + return mps.SpendableBalanceStorage +} diff --git a/core/service/mempoolCoreService_test.go b/core/service/mempoolCoreService_test.go index 48528b100..15093448a 100644 --- a/core/service/mempoolCoreService_test.go +++ b/core/service/mempoolCoreService_test.go @@ -44,22 +44,25 @@ var _ = mockMempoolTransaction func TestNewMempoolService(t *testing.T) { type args struct { - ct chaintype.ChainType - queryExecutor query.ExecutorInterface - mempoolQuery query.MempoolQueryInterface - merkleTreeQuery query.MerkleTreeQueryInterface - accountBalanceQuery query.AccountBalanceQueryInterface - transactionQuery query.TransactionQueryInterface - actionTypeSwitcher transaction.TypeActionSwitcher - obsr *observer.Observer - signature crypto.SignatureInterface - logger *log.Logger - transactionUtil transaction.UtilInterface - receiptUtil coreUtil.ReceiptUtilInterface - receiptService ReceiptServiceInterface - TransactionCoreService TransactionCoreServiceInterface - BlockStateStorage storage.CacheStackStorageInterface - MempoolCacheStorage storage.CacheStorageInterface + ct chaintype.ChainType + queryExecutor query.ExecutorInterface + mempoolQuery query.MempoolQueryInterface + merkleTreeQuery query.MerkleTreeQueryInterface + accountBalanceQuery query.AccountBalanceQueryInterface + transactionQuery query.TransactionQueryInterface + actionTypeSwitcher transaction.TypeActionSwitcher + obsr *observer.Observer + signature crypto.SignatureInterface + logger *log.Logger + transactionUtil transaction.UtilInterface + receiptUtil coreUtil.ReceiptUtilInterface + receiptService ReceiptServiceInterface + TransactionCoreService TransactionCoreServiceInterface + BlockStateStorage storage.CacheStackStorageInterface + MempoolCacheStorage storage.CacheStorageInterface + MempoolBackupStorage storage.CacheStorageInterface + MempoolUnsaveCacheStorage storage.CacheStorageInterface + SpendableBalanceStorage storage.CacheStorageInterface } test := struct { @@ -73,8 +76,9 @@ func TestNewMempoolService(t *testing.T) { obsr: observer.NewObserver(), }, want: &MempoolService{ - Chaintype: &chaintype.MainChain{}, - Observer: observer.NewObserver(), + Chaintype: &chaintype.MainChain{}, + Observer: observer.NewObserver(), + accountsUnsaveMempoolIDsMap: make(map[string]map[int64]bool), }, } @@ -95,7 +99,9 @@ func TestNewMempoolService(t *testing.T) { test.args.TransactionCoreService, test.args.BlockStateStorage, test.args.MempoolCacheStorage, - nil, + test.args.MempoolBackupStorage, + test.args.MempoolUnsaveCacheStorage, + test.args.SpendableBalanceStorage, ) if !reflect.DeepEqual(got, test.want) { @@ -473,6 +479,9 @@ type ( mockMempoolCacheStorageExpiryExist struct { storage.MempoolCacheStorage } + mockSpendableBalanceStorageDeleteExpiredMempoolTransactions struct { + storage.SpendableBalanceStorage + } ) func (*mockMempoolCacheStorageEmpty) GetAllItems(item interface{}) error { @@ -502,16 +511,17 @@ func (*mockMempoolCacheStorageExpiryExist) GetAllItems(item interface{}) error { func TestMempoolService_DeleteExpiredMempoolTransactions(t *testing.T) { type fields struct { - Chaintype chaintype.ChainType - QueryExecutor query.ExecutorInterface - MempoolQuery query.MempoolQueryInterface - ActionTypeSwitcher transaction.TypeActionSwitcher - AccountBalanceQuery query.AccountBalanceQueryInterface - Signature crypto.SignatureInterface - TransactionQuery query.TransactionQueryInterface - Observer *observer.Observer - MempoolCacheStorage storage.CacheStorageInterface - TransactionCoreService TransactionCoreServiceInterface + Chaintype chaintype.ChainType + QueryExecutor query.ExecutorInterface + MempoolQuery query.MempoolQueryInterface + ActionTypeSwitcher transaction.TypeActionSwitcher + AccountBalanceQuery query.AccountBalanceQueryInterface + Signature crypto.SignatureInterface + TransactionQuery query.TransactionQueryInterface + Observer *observer.Observer + MempoolCacheStorage storage.CacheStorageInterface + TransactionCoreService TransactionCoreServiceInterface + SpendableBalanceStorage storage.CacheStorageInterface } tests := []struct { name string @@ -535,7 +545,8 @@ func TestMempoolService_DeleteExpiredMempoolTransactions(t *testing.T) { ActionTypeSwitcher: &transaction.TypeSwitcher{ Executor: &mockQueryExecutorDeleteExpiredMempoolTransactions{}, }, - MempoolCacheStorage: &mockMempoolCacheStorageExpiryExist{}, + MempoolCacheStorage: &mockMempoolCacheStorageExpiryExist{}, + SpendableBalanceStorage: &mockSpendableBalanceStorageDeleteExpiredMempoolTransactions{}, TransactionCoreService: NewTransactionCoreService( log.New(), &mockQueryExecutorDeleteExpiredMempoolTransactions{}, @@ -555,16 +566,17 @@ func TestMempoolService_DeleteExpiredMempoolTransactions(t *testing.T) { TransactionUtil: &transaction.Util{ MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, }, - Chaintype: tt.fields.Chaintype, - QueryExecutor: tt.fields.QueryExecutor, - MempoolQuery: tt.fields.MempoolQuery, - ActionTypeSwitcher: tt.fields.ActionTypeSwitcher, - AccountBalanceQuery: tt.fields.AccountBalanceQuery, - Signature: tt.fields.Signature, - TransactionQuery: tt.fields.TransactionQuery, - Observer: tt.fields.Observer, - TransactionCoreService: tt.fields.TransactionCoreService, - MempoolCacheStorage: tt.fields.MempoolCacheStorage, + Chaintype: tt.fields.Chaintype, + QueryExecutor: tt.fields.QueryExecutor, + MempoolQuery: tt.fields.MempoolQuery, + ActionTypeSwitcher: tt.fields.ActionTypeSwitcher, + AccountBalanceQuery: tt.fields.AccountBalanceQuery, + Signature: tt.fields.Signature, + TransactionQuery: tt.fields.TransactionQuery, + Observer: tt.fields.Observer, + TransactionCoreService: tt.fields.TransactionCoreService, + MempoolCacheStorage: tt.fields.MempoolCacheStorage, + SpendableBalanceStorage: tt.fields.SpendableBalanceStorage, } if err := mps.DeleteExpiredMempoolTransactions(); (err != nil) != tt.wantErr { t.Errorf("DeleteExpiredMempoolTransactions() error = %v, wantErr %v", err, tt.wantErr) @@ -775,20 +787,21 @@ func (*mockMempoolCacheStorageFailGetItem) GetItem(key, item interface{}) error func TestMempoolService_ProcessReceivedTransaction(t *testing.T) { type fields struct { - Chaintype chaintype.ChainType - QueryExecutor query.ExecutorInterface - MempoolQuery query.MempoolQueryInterface - MerkleTreeQuery query.MerkleTreeQueryInterface - ActionTypeSwitcher transaction.TypeActionSwitcher - AccountBalanceQuery query.AccountBalanceQueryInterface - Signature crypto.SignatureInterface - TransactionQuery query.TransactionQueryInterface - Observer *observer.Observer - Logger *log.Logger - TransactionUtil transaction.UtilInterface - ReceiptUtil coreUtil.ReceiptUtilInterface - ReceiptService ReceiptServiceInterface - MempoolCacheStorage storage.CacheStorageInterface + Chaintype chaintype.ChainType + QueryExecutor query.ExecutorInterface + MempoolQuery query.MempoolQueryInterface + MerkleTreeQuery query.MerkleTreeQueryInterface + ActionTypeSwitcher transaction.TypeActionSwitcher + AccountBalanceQuery query.AccountBalanceQueryInterface + Signature crypto.SignatureInterface + TransactionQuery query.TransactionQueryInterface + Observer *observer.Observer + Logger *log.Logger + TransactionUtil transaction.UtilInterface + ReceiptUtil coreUtil.ReceiptUtilInterface + ReceiptService ReceiptServiceInterface + MempoolCacheStorage storage.CacheStorageInterface + MempoolUnsaveCacheStorage storage.CacheStorageInterface } type args struct { senderPublicKey, receivedTxBytes []byte @@ -810,8 +823,9 @@ func TestMempoolService_ProcessReceivedTransaction(t *testing.T) { { name: "Fail:ParseTransaction_error", fields: fields{ - TransactionUtil: &mockTransactionUtilErrorParse{}, - MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + TransactionUtil: &mockTransactionUtilErrorParse{}, + MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + MempoolUnsaveCacheStorage: &mockCacheStorageAlwaysSuccess{}, }, args: args{}, want: want{}, @@ -820,12 +834,13 @@ func TestMempoolService_ProcessReceivedTransaction(t *testing.T) { { name: "Fail:ValidateMempoolTransaction_error_non_duplicate", fields: fields{ - QueryExecutor: &mockGetMempoolTransactionsByBlockHeightExecutor{}, - MempoolQuery: query.NewMempoolQuery(chaintype.GetChainType(0)), - TransactionUtil: &mockTransactionUtilSuccess{}, - ReceiptUtil: &mockReceiptUtilSuccess{}, - ReceiptService: &mockReceiptServiceSucces{}, - MempoolCacheStorage: &mockMempoolCacheStorageFailGetItem{}, + QueryExecutor: &mockGetMempoolTransactionsByBlockHeightExecutor{}, + MempoolQuery: query.NewMempoolQuery(chaintype.GetChainType(0)), + TransactionUtil: &mockTransactionUtilSuccess{}, + ReceiptUtil: &mockReceiptUtilSuccess{}, + ReceiptService: &mockReceiptServiceSucces{}, + MempoolCacheStorage: &mockMempoolCacheStorageFailGetItem{}, + MempoolUnsaveCacheStorage: &mockMempoolCacheStorageFailGetItem{}, }, args: args{}, want: want{}, @@ -834,12 +849,13 @@ func TestMempoolService_ProcessReceivedTransaction(t *testing.T) { { name: "Fail:ValidateMempoolTransaction_error_duplicate_and_kv_executor_get_error_non_err_key_not_found", fields: fields{ - QueryExecutor: &mockGetMempoolTransactionsByBlockHeightExecutor{}, - MempoolQuery: query.NewMempoolQuery(chaintype.GetChainType(0)), - TransactionUtil: &mockTransactionUtilSuccess{}, - ReceiptUtil: &mockReceiptUtilSuccess{}, - ReceiptService: &mockReceiptServiceSucces{WantErr: true}, - MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + QueryExecutor: &mockGetMempoolTransactionsByBlockHeightExecutor{}, + MempoolQuery: query.NewMempoolQuery(chaintype.GetChainType(0)), + TransactionUtil: &mockTransactionUtilSuccess{}, + ReceiptUtil: &mockReceiptUtilSuccess{}, + ReceiptService: &mockReceiptServiceSucces{WantErr: true}, + MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + MempoolUnsaveCacheStorage: &mockCacheStorageAlwaysSuccess{}, }, args: args{}, want: want{}, @@ -848,12 +864,13 @@ func TestMempoolService_ProcessReceivedTransaction(t *testing.T) { { name: "Fail:ValidateMempoolTransaction_error_duplicate_and_kv_executor_found_the_record_the_sender_has_received_receipt_for_this_data", fields: fields{ - QueryExecutor: &mockGetMempoolTransactionsByBlockHeightExecutor{}, - MempoolQuery: query.NewMempoolQuery(chaintype.GetChainType(0)), - TransactionUtil: &mockTransactionUtilSuccess{}, - ReceiptUtil: &mockReceiptUtilSuccess{}, - ReceiptService: &mockReceiptServiceSucces{WantDuplicated: true}, - MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + QueryExecutor: &mockGetMempoolTransactionsByBlockHeightExecutor{}, + MempoolQuery: query.NewMempoolQuery(chaintype.GetChainType(0)), + TransactionUtil: &mockTransactionUtilSuccess{}, + ReceiptUtil: &mockReceiptUtilSuccess{}, + ReceiptService: &mockReceiptServiceSucces{WantDuplicated: true}, + MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + MempoolUnsaveCacheStorage: &mockCacheStorageAlwaysSuccess{}, }, args: args{}, want: want{}, @@ -863,36 +880,37 @@ func TestMempoolService_ProcessReceivedTransaction(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mps := &MempoolService{ - Chaintype: tt.fields.Chaintype, - MerkleTreeQuery: tt.fields.MerkleTreeQuery, - ActionTypeSwitcher: tt.fields.ActionTypeSwitcher, - AccountBalanceQuery: tt.fields.AccountBalanceQuery, - Signature: tt.fields.Signature, - TransactionQuery: tt.fields.TransactionQuery, - Observer: tt.fields.Observer, - Logger: tt.fields.Logger, - TransactionUtil: tt.fields.TransactionUtil, - ReceiptUtil: tt.fields.ReceiptUtil, - ReceiptService: tt.fields.ReceiptService, - QueryExecutor: tt.fields.QueryExecutor, - MempoolCacheStorage: tt.fields.MempoolCacheStorage, + Chaintype: tt.fields.Chaintype, + MerkleTreeQuery: tt.fields.MerkleTreeQuery, + ActionTypeSwitcher: tt.fields.ActionTypeSwitcher, + AccountBalanceQuery: tt.fields.AccountBalanceQuery, + Signature: tt.fields.Signature, + TransactionQuery: tt.fields.TransactionQuery, + Observer: tt.fields.Observer, + Logger: tt.fields.Logger, + TransactionUtil: tt.fields.TransactionUtil, + ReceiptUtil: tt.fields.ReceiptUtil, + ReceiptService: tt.fields.ReceiptService, + QueryExecutor: tt.fields.QueryExecutor, + MempoolCacheStorage: tt.fields.MempoolCacheStorage, + MempoolUnsaveCacheStorage: tt.fields.MempoolUnsaveCacheStorage, } - batchReceipt, tx, err := mps.ProcessReceivedTransaction( + batchReceipt, tx, err := mps.processeReceiptAndValidateTransactionP2P( tt.args.senderPublicKey, tt.args.receivedTxBytes, tt.args.lastBlock, tt.args.nodeSecretPhrase, ) if (err != nil) != tt.wantErr { - t.Errorf("ProcessReceivedTransaction() error = %v, wantErr %v", err, tt.want.err) + t.Errorf("processeReceiptAndValidateTransactionP2P() error = %v, wantErr %v", err, tt.want.err) return } if !reflect.DeepEqual(batchReceipt, tt.want.batchReceipt) { - t.Errorf("ProcessReceivedTransaction() batchReceipt = \n%v, want \n%v", batchReceipt, tt.want.batchReceipt) + t.Errorf("processeReceiptAndValidateTransactionP2P() batchReceipt = \n%v, want \n%v", batchReceipt, tt.want.batchReceipt) return } if !reflect.DeepEqual(tx, tt.want.transaction) { - t.Errorf("ProcessReceivedTransaction() transaction = \n%v, want \n%v", tx, tt.want.transaction) + t.Errorf("processeReceiptAndValidateTransactionP2P() transaction = \n%v, want \n%v", tx, tt.want.transaction) } }) } @@ -907,7 +925,7 @@ type ( } ) -func (*mockEscrowTypeAction) EscrowApplyUnconfirmed() error { +func (*mockEscrowTypeAction) EscrowApplyUnconfirmed(applyInCache bool) error { return nil } func (*mockTxTypeSuccess) ApplyUnconfirmed() error { @@ -1183,15 +1201,16 @@ func TestMempoolService_ValidateMempoolTransaction(t *testing.T) { successTx.Signature, _ = (&crypto.Signature{}).Sign(txBytesHash[:], model.AccountType_ZbcAccountType, "concur vocalist rotten busload gap quote stinging undiluted surfer goofiness deviation starved") type fields struct { - Chaintype chaintype.ChainType - QueryExecutor query.ExecutorInterface - MempoolQuery query.MempoolQueryInterface - ActionTypeSwitcher transaction.TypeActionSwitcher - AccountBalanceQuery query.AccountBalanceQueryInterface - TransactionQuery query.TransactionQueryInterface - Observer *observer.Observer - TransactionCoreService TransactionCoreServiceInterface - MempoolCacheStorage storage.CacheStorageInterface + Chaintype chaintype.ChainType + QueryExecutor query.ExecutorInterface + MempoolQuery query.MempoolQueryInterface + ActionTypeSwitcher transaction.TypeActionSwitcher + AccountBalanceQuery query.AccountBalanceQueryInterface + TransactionQuery query.TransactionQueryInterface + Observer *observer.Observer + TransactionCoreService TransactionCoreServiceInterface + MempoolCacheStorage storage.CacheStorageInterface + MempoolUnsaveCacheStorage storage.CacheStorageInterface } type args struct { mpTx *model.Transaction @@ -1219,7 +1238,8 @@ func TestMempoolService_ValidateMempoolTransaction(t *testing.T) { nil, nil, ), - MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + MempoolUnsaveCacheStorage: &mockCacheStorageAlwaysSuccess{}, }, args: args{ mpTx: successTx, @@ -1229,12 +1249,13 @@ func TestMempoolService_ValidateMempoolTransaction(t *testing.T) { { name: "wantErr:TransactionExisted", fields: fields{ - Chaintype: &chaintype.MainChain{}, - QueryExecutor: &mockExecutorValidateMempoolTransactionSuccess{}, - MempoolQuery: query.NewMempoolQuery(&chaintype.MainChain{}), - ActionTypeSwitcher: &transaction.TypeSwitcher{}, - TransactionQuery: query.NewTransactionQuery(&chaintype.MainChain{}), - MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + Chaintype: &chaintype.MainChain{}, + QueryExecutor: &mockExecutorValidateMempoolTransactionSuccess{}, + MempoolQuery: query.NewMempoolQuery(&chaintype.MainChain{}), + ActionTypeSwitcher: &transaction.TypeSwitcher{}, + TransactionQuery: query.NewTransactionQuery(&chaintype.MainChain{}), + MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + MempoolUnsaveCacheStorage: &mockCacheStorageAlwaysSuccess{}, }, args: args{ mpTx: transaction.GetFixturesForTransaction( @@ -1251,12 +1272,13 @@ func TestMempoolService_ValidateMempoolTransaction(t *testing.T) { { name: "wantErr:TransactionExisted", fields: fields{ - Chaintype: &chaintype.MainChain{}, - QueryExecutor: &mockExecutorValidateMempoolTransactionFail{}, - TransactionQuery: query.NewTransactionQuery(&chaintype.MainChain{}), - MempoolQuery: query.NewMempoolQuery(&chaintype.MainChain{}), - ActionTypeSwitcher: &transaction.TypeSwitcher{}, - MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + Chaintype: &chaintype.MainChain{}, + QueryExecutor: &mockExecutorValidateMempoolTransactionFail{}, + TransactionQuery: query.NewTransactionQuery(&chaintype.MainChain{}), + MempoolQuery: query.NewMempoolQuery(&chaintype.MainChain{}), + ActionTypeSwitcher: &transaction.TypeSwitcher{}, + MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + MempoolUnsaveCacheStorage: &mockCacheStorageAlwaysSuccess{}, }, args: args{ mpTx: transaction.GetFixturesForTransaction( @@ -1273,12 +1295,13 @@ func TestMempoolService_ValidateMempoolTransaction(t *testing.T) { { name: "wantErr:ParseFail", fields: fields{ - Chaintype: &chaintype.MainChain{}, - QueryExecutor: &mockExecutorValidateMempoolTransactionSuccessNoRow{}, - TransactionQuery: query.NewTransactionQuery(&chaintype.MainChain{}), - MempoolQuery: query.NewMempoolQuery(&chaintype.MainChain{}), - ActionTypeSwitcher: &transaction.TypeSwitcher{}, - MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + Chaintype: &chaintype.MainChain{}, + QueryExecutor: &mockExecutorValidateMempoolTransactionSuccessNoRow{}, + TransactionQuery: query.NewTransactionQuery(&chaintype.MainChain{}), + MempoolQuery: query.NewMempoolQuery(&chaintype.MainChain{}), + ActionTypeSwitcher: &transaction.TypeSwitcher{}, + MempoolCacheStorage: &mockCacheStorageAlwaysSuccess{}, + MempoolUnsaveCacheStorage: &mockCacheStorageAlwaysSuccess{}, }, args: args{ mpTx: &model.Transaction{ @@ -1302,8 +1325,9 @@ func TestMempoolService_ValidateMempoolTransaction(t *testing.T) { QueryExecutor: &mockQueryExecutoMempoolCoreService{}, AccountDatasetQuery: &mockAccountDatasetQueryMempoolCoreService{wantNoRow: true}, }, - TransactionCoreService: tt.fields.TransactionCoreService, - MempoolCacheStorage: tt.fields.MempoolCacheStorage, + TransactionCoreService: tt.fields.TransactionCoreService, + MempoolCacheStorage: tt.fields.MempoolCacheStorage, + MempoolUnsaveCacheStorage: tt.fields.MempoolUnsaveCacheStorage, } if err := mps.ValidateMempoolTransaction(tt.args.mpTx); (err != nil) != tt.wantErr { t.Errorf("MempoolServiceUtil.ValidateMempoolTransaction() error = %v, wantErr %v", err, tt.wantErr) diff --git a/core/service/snapshotMainBlockService.go b/core/service/snapshotMainBlockService.go index 03a39a141..a224c074b 100644 --- a/core/service/snapshotMainBlockService.go +++ b/core/service/snapshotMainBlockService.go @@ -279,7 +279,7 @@ func (ss *SnapshotMainBlockService) ImportSnapshotFile(snapshotFileInfo *model.S if err != nil { return err } - err = txType.ApplyUnconfirmed() + err = txType.ApplyUnconfirmed(false) if err != nil { return err } diff --git a/core/service/transactionCoreService.go b/core/service/transactionCoreService.go index c33fc9902..2295da7ab 100644 --- a/core/service/transactionCoreService.go +++ b/core/service/transactionCoreService.go @@ -17,7 +17,7 @@ type ( GetTransactionsByIds(transactionIds []int64) ([]*model.Transaction, error) GetTransactionsByBlockID(blockID int64) ([]*model.Transaction, error) ValidateTransaction(txAction transaction.TypeAction, useTX bool) error - ApplyUnconfirmedTransaction(txAction transaction.TypeAction) error + ApplyUnconfirmedTransaction(txAction transaction.TypeAction, applyInCache bool) error UndoApplyUnconfirmedTransaction(txAction transaction.TypeAction) error ApplyConfirmedTransaction(txAction transaction.TypeAction, blockTimestamp int64) error ExpiringEscrowTransactions(blockHeight uint32, blockTimestamp int64, useTX bool) error @@ -317,21 +317,19 @@ func (tg *TransactionCoreService) ValidateTransaction(txAction transaction.TypeA } } -func (tg *TransactionCoreService) ApplyUnconfirmedTransaction(txAction transaction.TypeAction) error { - +func (tg *TransactionCoreService) ApplyUnconfirmedTransaction(txAction transaction.TypeAction, applyInCache bool) error { escrowAction, ok := txAction.Escrowable() switch ok { case true: - err := escrowAction.EscrowApplyUnconfirmed() + err := escrowAction.EscrowApplyUnconfirmed(applyInCache) return err default: - err := txAction.ApplyUnconfirmed() + err := txAction.ApplyUnconfirmed(applyInCache) return err } } func (tg *TransactionCoreService) UndoApplyUnconfirmedTransaction(txAction transaction.TypeAction) error { - escrowAction, ok := txAction.Escrowable() switch ok { case true: diff --git a/core/service/transactionCoreService_test.go b/core/service/transactionCoreService_test.go index 9c99421b8..c0eae5ace 100644 --- a/core/service/transactionCoreService_test.go +++ b/core/service/transactionCoreService_test.go @@ -13,6 +13,7 @@ import ( "github.com/zoobc/zoobc-core/common/chaintype" "github.com/zoobc/zoobc-core/common/model" "github.com/zoobc/zoobc-core/common/query" + "github.com/zoobc/zoobc-core/common/storage" "github.com/zoobc/zoobc-core/common/transaction" ) @@ -381,6 +382,9 @@ type ( mockQueryExecutorExpiringEscrowSuccess struct { query.ExecutorInterface } + mockSpendableBalanceCacheExpiringEscrowSuccess struct { + storage.SpendableBalanceStorage + } ) func (*mockQueryExecutorExpiringEscrowSuccess) BeginTx() error { @@ -453,6 +457,10 @@ func (*mockQueryExecutorExpiringEscrowSuccess) ExecuteTransactions(queries [][]i return nil } +func (*mockSpendableBalanceCacheExpiringEscrowSuccess) GetItem(key, item interface{}) error { + return nil +} + func TestTransactionCoreService_ExpiringEscrowTransactions(t *testing.T) { type fields struct { TransactionQuery query.TransactionQueryInterface @@ -475,7 +483,10 @@ func TestTransactionCoreService_ExpiringEscrowTransactions(t *testing.T) { TransactionQuery: query.NewTransactionQuery(&chaintype.MainChain{}), EscrowTransactionQuery: query.NewEscrowTransactionQuery(), QueryExecutor: &mockQueryExecutorExpiringEscrowSuccess{}, - TypeActionSwitcher: &transaction.TypeSwitcher{Executor: &mockQueryExecutorExpiringEscrowSuccess{}}, + TypeActionSwitcher: &transaction.TypeSwitcher{ + Executor: &mockQueryExecutorExpiringEscrowSuccess{}, + SpendabelBalanceStorage: &mockSpendableBalanceCacheExpiringEscrowSuccess{}, + }, }, }, } @@ -644,7 +655,7 @@ type mockApplyUnconfirmedTransactionEscrowApplyUnconfirmed struct { transaction.EscrowTypeAction } -func (*mockApplyUnconfirmedTransactionEscrowApplyUnconfirmed) EscrowApplyUnconfirmed() error { +func (*mockApplyUnconfirmedTransactionEscrowApplyUnconfirmed) EscrowApplyUnconfirmed(applyInCache bool) error { return nil } @@ -663,7 +674,7 @@ type mockApplyUnconfirmedTransactionEscrowFalse struct { func (*mockApplyUnconfirmedTransactionEscrowFalse) Escrowable() (transaction.EscrowTypeAction, bool) { return nil, false } -func (*mockApplyUnconfirmedTransactionEscrowFalse) ApplyUnconfirmed() error { +func (*mockApplyUnconfirmedTransactionEscrowFalse) ApplyUnconfirmed(bool) error { return nil } @@ -674,7 +685,8 @@ func TestTransactionCoreService_ApplyUnconfirmedTransaction(t *testing.T) { QueryExecutor query.ExecutorInterface } type args struct { - txAction transaction.TypeAction + txAction transaction.TypeAction + applyInCache bool } tests := []struct { name string @@ -682,7 +694,6 @@ func TestTransactionCoreService_ApplyUnconfirmedTransaction(t *testing.T) { args args wantErr bool }{ - // TODO: Add test cases. { name: "ApplyUnconfirmedTransaction:EscrowTrue", args: args{ @@ -705,7 +716,7 @@ func TestTransactionCoreService_ApplyUnconfirmedTransaction(t *testing.T) { EscrowTransactionQuery: tt.fields.EscrowTransactionQuery, QueryExecutor: tt.fields.QueryExecutor, } - if err := tg.ApplyUnconfirmedTransaction(tt.args.txAction); (err != nil) != tt.wantErr { + if err := tg.ApplyUnconfirmedTransaction(tt.args.txAction, tt.args.applyInCache); (err != nil) != tt.wantErr { t.Errorf("TransactionCoreService.ApplyUnconfirmedTransaction() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/main.go b/main.go index 530d50571..1eb5efc35 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,6 @@ import ( "encoding/binary" "encoding/hex" "fmt" - "github.com/zoobc/zoobc-core/common/feedbacksystem" "net/http" _ "net/http/pprof" "os" @@ -31,6 +30,7 @@ import ( "github.com/zoobc/zoobc-core/common/crypto" "github.com/zoobc/zoobc-core/common/database" "github.com/zoobc/zoobc-core/common/fee" + "github.com/zoobc/zoobc-core/common/feedbacksystem" "github.com/zoobc/zoobc-core/common/model" "github.com/zoobc/zoobc-core/common/monitoring" "github.com/zoobc/zoobc-core/common/query" @@ -60,7 +60,8 @@ var ( nextNodeAdmissionStorage, mempoolStorage, receiptReminderStorage storage.CacheStorageInterface mempoolBackupStorage, batchReceiptCacheStorage storage.CacheStorageInterface activeNodeRegistryCacheStorage, pendingNodeRegistryCacheStorage storage.CacheStorageInterface - nodeAddressInfoStorage storage.CacheStorageInterface + nodeAddressInfoStorage, spendableBalanceStorage storage.CacheStorageInterface + mempoolUnsaveCacheStorage storage.CacheStorageInterface scrambleNodeStorage, mainBlocksStorage, spineBlocksStorage storage.CacheStackStorageInterface blockStateStorages = make(map[int32]storage.CacheStorageInterface) snapshotChunkUtil util.ChunkUtilInterface @@ -292,14 +293,17 @@ func initiateMainInstance() { blockStateStorages[spinechain.GetTypeInt()] = spineBlockStateStorage nextNodeAdmissionStorage = storage.NewNodeAdmissionTimestampStorage() nodeShardStorage = storage.NewNodeShardCacheStorage() - mempoolStorage = storage.NewMempoolStorage() + mempoolStorage = storage.NewMempoolStorage(monitoring.TypeMempoolCacheStorage, monitoring.TypeMempoolCountCacheStorage) + mempoolBackupStorage = storage.NewMempoolBackupStorage() + mempoolUnsaveCacheStorage = storage.NewMempoolStorage(monitoring.TypeMempoolUnsaveCacheStorage, monitoring.TypeMempoolUnsaveCountCacheStorage) scrambleNodeStorage = storage.NewScrambleCacheStackStorage() receiptReminderStorage = storage.NewReceiptReminderStorage() - mempoolBackupStorage = storage.NewMempoolBackupStorage() batchReceiptCacheStorage = storage.NewReceiptPoolCacheStorage() nodeAddressInfoStorage = storage.NewNodeAddressInfoStorage() mainBlocksStorage = storage.NewBlocksStorage() spineBlocksStorage = storage.NewBlocksStorage() + spendableBalanceStorage = storage.NewSpendableBalanceStorage() + // store current active node registry (not in queue) activeNodeRegistryCacheStorage = storage.NewNodeRegistryCacheStorage( monitoring.TypeActiveNodeRegistryStorage, @@ -358,6 +362,7 @@ func initiateMainInstance() { NodeAddressInfoStorage: txNodeAddressInfoStorage, ActiveNodeRegistryStorage: txActiveNodeRegistryStorage, PendingNodeRegistryStorage: txPendingNodeRegistryStorage, + SpendabelBalanceStorage: spendableBalanceStorage, FeeScaleService: feeScaleService, } @@ -519,6 +524,8 @@ func initiateMainInstance() { mainBlocksStorage, mempoolStorage, mempoolBackupStorage, + mempoolUnsaveCacheStorage, + spendableBalanceStorage, ) mainchainBlockService = service.NewBlockMainService( @@ -1083,6 +1090,13 @@ func startScheduler() { ); err != nil { loggerCoreService.Error("Scheduler Err: ", err.Error()) } + if err := schedulerInstance.AddJob( + constant.MempoolMoveFullCachePeriod, + mempoolService.MoveFullCacheMempools, + ); err != nil { + loggerCoreService.Error("Scheduler Err: ", err.Error()) + } + } func startBlockchainSynchronizers() { diff --git a/p2p/service/p2pServerService.go b/p2p/service/p2pServerService.go index b4c4e76bb..65cec5c52 100644 --- a/p2p/service/p2pServerService.go +++ b/p2p/service/p2pServerService.go @@ -509,7 +509,7 @@ func (ps *P2PServerService) SendTransaction( "mempoolServiceNotFoundByThisChainType", ) } - receipt, err := mempoolService.ReceivedTransaction( + receipt, err := mempoolService.ReceivedTransactionFromP2P( senderPublicKey, transactionBytes, lastBlockCacheFormat, diff --git a/p2p/service/p2pServerService_test.go b/p2p/service/p2pServerService_test.go index b753643e0..54b0f727e 100644 --- a/p2p/service/p2pServerService_test.go +++ b/p2p/service/p2pServerService_test.go @@ -1340,14 +1340,18 @@ func (*mockSendTransactionBlockServiceSuccess) GetLastBlockCacheFormat() (*stora BlockHash: mockBlock.BlockHash, }, nil } -func (*mockSendTransactionMempoolServiceReceivedTransactionFail) ReceivedTransaction( - []byte, []byte, *storage.BlockCacheObject, string, +func (*mockSendTransactionMempoolServiceReceivedTransactionFail) ReceivedTransactionFromP2P( + senderPublicKey, receivedTxBytes []byte, + lastBlockCacheFromat *storage.BlockCacheObject, + nodeSecretPhrase string, ) (*model.Receipt, error) { return nil, errors.New("mock Error") } -func (*mockSendTransactionMempoolServiceSuccess) ReceivedTransaction( - []byte, []byte, *storage.BlockCacheObject, string, +func (*mockSendTransactionMempoolServiceSuccess) ReceivedTransactionFromP2P( + senderPublicKey, receivedTxBytes []byte, + lastBlockCacheFromat *storage.BlockCacheObject, + nodeSecretPhrase string, ) (*model.Receipt, error) { return &model.Receipt{ SenderPublicKey: []byte{1},