diff --git a/.gitignore b/.gitignore index 4e0245a09..3ee901e98 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,6 @@ accounts.txt .editorconfig .manual release/ -github.token \ No newline at end of file +github.token +*.back +*.bak diff --git a/api/handler/multisigHandler.go b/api/handler/multisigHandler.go index 560bc97ed..b3913a877 100644 --- a/api/handler/multisigHandler.go +++ b/api/handler/multisigHandler.go @@ -3,12 +3,10 @@ package handler import ( "context" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/zoobc/zoobc-core/api/service" - "github.com/zoobc/zoobc-core/common/model" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) type ( @@ -28,8 +26,8 @@ func (msh *MultisigHandler) GetPendingTransactions( req.Pagination.OrderField = "block_height" req.Pagination.OrderBy = model.OrderBy_DESC } - result, err := msh.MultisigService.GetPendingTransactions(req) - return result, err + + return msh.MultisigService.GetPendingTransactions(req) } func (msh *MultisigHandler) GetPendingTransactionDetailByTransactionHash( diff --git a/cmd/block/blockGenerator.go b/cmd/block/blockGenerator.go index 796da680a..af0a53b66 100644 --- a/cmd/block/blockGenerator.go +++ b/cmd/block/blockGenerator.go @@ -186,9 +186,13 @@ func initialize( receiptUtil, publishedReceiptUtil, service.NewTransactionCoreService( + nil, queryExecutor, + nil, + nil, query.NewTransactionQuery(chainType), nil, + nil, ), nil, nil, diff --git a/cmd/readme.md b/cmd/readme.md index fde6a272f..ba9f6ce3e 100644 --- a/cmd/readme.md +++ b/cmd/readme.md @@ -22,12 +22,14 @@ Command line interface to as a utility tools to develop the zoobc system. - `go run main {command} --help` to see to see available subcommands and flags - `go run main {command} {subcommand} --help` to see to see available subcommands and flags of subcommand +## Transaction Commands ### Transaction general flag - `--output` to provide generated ouput type. Example: `--ouput bytes` - `--version` to provide version of transaction. Example: `--version 1` - `--timestamp` to provide timestamp of trasaction. Example: `--timestamp 1234567` - `--sender-seed` to provide the seed of sender transaction. Example: `--sender-seed "concur vocalist rotten busload gap quote stinging undiluted surfer goofiness deviation starved"` +- `--sender-address` transaction's sender address - `--recipient` provide recepient transaction. Example `--recipient VZvYd80p5S-rxSNQmMZwYXC7LyAzBmcfcj4MUUAdudWM` - `--fee` to provide fee transaction, Example `--fee 1` - `--post` to define automate post transaction or not. Example: `-post true` @@ -40,7 +42,7 @@ Command line interface to as a utility tools to develop the zoobc system. go run main.go generate transaction send-money --timestamp 1257894000 --sender-seed "concur vocalist rotten busload gap quote stinging undiluted surfer goofiness deviation starved" --recipient VZvYd80p5S-rxSNQmMZwYXC7LyAzBmcfcj4MUUAdudWM --amount 5000000000 ``` -#### Transaction send money escrow, set flag `--escrow true` and 3 more fields: `--approver-address`, `--timeout`, `--commission` and `--instruction` +### Transaction send money escrow, set flag `--escrow true` and 3 more fields: `--approver-address`, `--timeout`, `--commission` and `--instruction` ```bash go run main.go generate transaction send-money --escrow true --approver-address BCZEGOb3WNx3fDOVf9ZS4EjvOIv_UeW4TVBQJ_6tHKlE --timeout 200 --sender-seed "execute beach inflict session course dance vanish cover lawsuit earth casino fringe waste warfare also habit skull donate window cannon scene salute dawn good" --amount 1111 --commission 111 --instruction "Check amount should be 111" --recipient nK_ouxdDDwuJiogiDAi_zs1LqeN7f5ZsXbFtXGqGc0Pd @@ -88,12 +90,34 @@ go run main.go generate transaction remove-account-dataset --timestamp 125789400 go run main.go generate transaction escrow-approval --transaction-id -2546596465476625657 --approval true --sender-seed "concur vocalist rotten busload gap quote stinging undiluted surfer goofiness deviation starved" --fee 111 ``` +### Transaction Multi Signatures +```bash +Flags: + --address-signatures stringToString address:signature list --address1='signature1' --address2='signature2' (default []) + --addresses strings list of participants --addresses='address1,address2' + -h, --help help for multi-signature + --min-signature uint32 minimum number of signature required for the transaction to be valid + --nonce int random number / access code for the multisig info + --transaction-hash string hash of transaction being signed by address-signature list hex + --unsigned-transaction string hex string of the unsigned transaction bytes +``` +For the multi signature transaction let say want to send money with multisig account, need to do this steps: +1. Generate transaction send money, make sure with argument `--hash`. It will be `--unsigned-transaction` value on multi signature generator. +2. Sign the transaction to get the transaction hash, and it will be `--transcation-has` and the last the `signature-hex` will be as `--address-signatures` value on multi signature generator.
+ +So the completed comment it will be: +```bash +go run main.go generate transaction multi-signature --sender-seed="execute beach inflict session course dance vanish cover lawsuit earth casino fringe waste warfare also habit skull donate window cannon scene salute dawn good" --unsigned-transaction="01000000012ba5ba5e000000002c000000486c5a4c683356636e4e6c764279576f417a584f51326a416c77464f69794f395f6e6a49336f7135596768612c000000486c38393154655446784767574f57664f4f464b59725f586468584e784f384a4b38576e4d4a56366738614c41420f0000000000080000000600000000000000000000000000000000000000000000000000000000000000" --transaction-hash="21ddbdada9903da81bf17dba6569ff7e2665fec38760c7f6636419ee30da65b0" --address-signatures="HlZLh3VcnNlvByWoAzXOQ2jAlwFOiyO9_njI3oq5Ygha=00000000b4efe21822c9d63818d8d19f6c608d917b2237426d1157b4e6689b22ce6c256ccf8ec8e2c1016ab09dd4ef2b01191fe2df70b7a123fec7115d7afd5a938f9b0a" +``` + +## Block Commands ### Block Generating Fake Blocks ```bash go run main.go generate block fake-blocks --numberOfBlocks=1000 --blocksmithSecretPhrase='sprinkled sneak species pork outpost thrift unwind cheesy vexingly dizzy neurology neatness' --out='../resource/zoobc.db' ``` +## Account Commands ### Account Generate Using Ed25519 Algorithm ```bash @@ -114,30 +138,28 @@ go run main.go generate account bitcoin --seed "concur vocalist rotten busload g go run main.go generate account multisig --addresses "BCZnSfqpP5tqFQlMTYkDeBVFWnbyVK7vLr5ORFpTjgtN" --addresses "BCZD_VxfO2S9aziIL3cn_cXW7uPDVPOrnXuP98GEAUC7" --addresses "BCZKLvgUYZ1KKx-jtF9KoJskjVPvB9jpIjfzzI6zDW0J" —-min-sigs=2 --nonce=3 ``` +## Other Commands +```bash go run main.go genesis generate +``` outputs cmd/genesis.go.new and cmd/cluster_config.json ```bash - ### Genesis Generate From cmd/genesisblock/preRegisteredNodes.json and resource/zoobc.db ``` - +```bash go run main.go genesis generate -w +``` outputs cmd/genesis.go.new and cmd/cluster_config.json -```bash - -### Genesis Generate From cmd/genesisblock/preRegisteredNodes.json and resource/zoobc.db, plus n random nodes registrations -``` +### Genesis Generate From cmd/genesisblock/preRegisteredNodes.json and resource/zoobc.db, plus n random nodes registrations +```bash go run main.go genesis generate -w -n 10 -outputs cmd/genesis.go.new and cmd/cluster_config.json - -``` - ``` +outputs cmd/genesis.go.new and cmd/cluster_config.json ### Generate Proof of Ownership Node Registry diff --git a/common/query/multisignatureInfoQuery.go b/common/query/multisignatureInfoQuery.go index a76e5867f..8a22246b9 100644 --- a/common/query/multisignatureInfoQuery.go +++ b/common/query/multisignatureInfoQuery.go @@ -63,7 +63,7 @@ func (msi *MultisignatureInfoQuery) GetMultisignatureInfoByAddress( } } -// InsertPendingSignature inserts a new pending transaction into DB +// InsertMultisignatureInfo inserts a new pending transaction into DB func (msi *MultisignatureInfoQuery) InsertMultisignatureInfo(multisigInfo *model.MultiSignatureInfo) [][]interface{} { var queries [][]interface{} insertQuery := fmt.Sprintf("INSERT OR REPLACE INTO %s (%s) VALUES(%s)", diff --git a/common/query/pendingTransactionQuery.go b/common/query/pendingTransactionQuery.go index b40560317..6f264a71c 100644 --- a/common/query/pendingTransactionQuery.go +++ b/common/query/pendingTransactionQuery.go @@ -5,6 +5,8 @@ import ( "fmt" "strings" + "github.com/zoobc/zoobc-core/common/constant" + "github.com/zoobc/zoobc-core/common/model" ) @@ -22,6 +24,7 @@ type ( ) ( str string, args []interface{}, ) + GetPendingTransactionsExpireByHeight(blockHeight uint32) (str string, args []interface{}) InsertPendingTransaction(pendingTx *model.PendingTransaction) [][]interface{} Scan(pendingTx *model.PendingTransaction, row *sql.Row) error ExtractModel(pendingTx *model.PendingTransaction) []interface{} @@ -103,6 +106,20 @@ func (ptq *PendingTransactionQuery) GetPendingTransactionsBySenderAddress( } } +// GetPendingTransactionsExpireByHeight presents query to get pending_transactions that was expire by block_height +func (ptq *PendingTransactionQuery) GetPendingTransactionsExpireByHeight(currentHeight uint32) (str string, args []interface{}) { + return fmt.Sprintf( + "SELECT %s FROM %s WHERE block_height = ? AND status = ? AND latest = ?", + strings.Join(ptq.Fields, ", "), + ptq.getTableName(), + ), + []interface{}{ + currentHeight - constant.MinRollbackBlocks, + model.PendingTransactionStatus_PendingTransactionPending, + true, + } +} + // InsertPendingTransaction inserts a new pending transaction into DB func (ptq *PendingTransactionQuery) InsertPendingTransaction(pendingTx *model.PendingTransaction) [][]interface{} { var queries [][]interface{} diff --git a/common/query/pendingTransactionQuery_test.go b/common/query/pendingTransactionQuery_test.go index b0bffd8b1..290401acf 100644 --- a/common/query/pendingTransactionQuery_test.go +++ b/common/query/pendingTransactionQuery_test.go @@ -567,3 +567,51 @@ func TestPendingTransactionQuery_TrimDataBeforeSnapshot(t *testing.T) { }) } } + +func TestPendingTransactionQuery_GetPendingTransactionsExpireByHeight(t *testing.T) { + type fields struct { + Fields []string + TableName string + } + type args struct { + currentHeight uint32 + } + tests := []struct { + name string + fields fields + args args + wantStr string + wantArgs []interface{} + }{ + { + name: "WantSuccess", + fields: fields(*NewPendingTransactionQuery()), + args: args{ + currentHeight: 1000, + }, + wantStr: "SELECT sender_address, transaction_hash, transaction_bytes, status, block_height, latest " + + "FROM pending_transaction WHERE block_height = ? AND status = ? AND latest = ?", + wantArgs: []interface{}{ + uint32(1000) - constant.MinRollbackBlocks, + model.PendingTransactionStatus_PendingTransactionPending, + true, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ptq := &PendingTransactionQuery{ + Fields: tt.fields.Fields, + TableName: tt.fields.TableName, + } + gotStr, gotArgs := ptq.GetPendingTransactionsExpireByHeight(tt.args.currentHeight) + if gotStr != tt.wantStr { + t.Errorf("GetPendingTransactionsExpireByHeight() gotStr = %v, want %v", gotStr, tt.wantStr) + return + } + if !reflect.DeepEqual(gotArgs, tt.wantArgs) { + t.Errorf("GetPendingTransactionsExpireByHeight() gotArgs = %v, want %v", gotArgs, tt.wantArgs) + } + }) + } +} diff --git a/core/service/blockMainService.go b/core/service/blockMainService.go index 87b6aa764..abc050f60 100644 --- a/core/service/blockMainService.go +++ b/core/service/blockMainService.go @@ -408,11 +408,18 @@ func (bs *BlockService) PushBlock(previousBlock, block *model.Block, broadcast, return err } - // Respecting Expiring escrow before push block process + /* + Expiring Process: expiring the the transactions that affected by current block height. + Respecting Expiring escrow and multi signature transaction before push block process + */ err = bs.TransactionCoreService.ExpiringEscrowTransactions(block.GetHeight(), true) if err != nil { return blocker.NewBlocker(blocker.BlockErr, err.Error()) } + err = bs.TransactionCoreService.ExpiringPendingTransactions(block.GetHeight(), true) + if err != nil { + return blocker.NewBlocker(blocker.BlockErr, err.Error()) + } blockInsertQuery, blockInsertValue := bs.BlockQuery.InsertBlock(block) err = bs.QueryExecutor.ExecuteTransaction(blockInsertQuery, blockInsertValue...) diff --git a/core/service/blockMainService_test.go b/core/service/blockMainService_test.go index df99437c3..8ce4f2371 100644 --- a/core/service/blockMainService_test.go +++ b/core/service/blockMainService_test.go @@ -335,10 +335,10 @@ func (*mockQueryExecutorSuccess) BeginTx() error { return nil } func (*mockQueryExecutorSuccess) RollbackTx() error { return nil } -func (*mockQueryExecutorSuccess) ExecuteTransaction(qStr string, args ...interface{}) error { +func (*mockQueryExecutorSuccess) ExecuteTransaction(string, ...interface{}) error { return nil } -func (*mockQueryExecutorSuccess) ExecuteTransactions(queries [][]interface{}) error { +func (*mockQueryExecutorSuccess) ExecuteTransactions([][]interface{}) error { return nil } func (*mockQueryExecutorSuccess) CommitTx() error { return nil } @@ -577,6 +577,9 @@ func (*mockQueryExecutorSuccess) ExecuteSelect(qe string, tx bool, args ...inter mockTransaction.GetSenderAccountAddress(), mockTransaction.GetRecipientAccountAddress(), )) + case "SELECT sender_address, transaction_hash, transaction_bytes, status, block_height, latest " + + "FROM pending_transaction WHERE block_height = ? AND status = ? AND latest = ?": + mock.ExpectQuery(regexp.QuoteMeta(qe)).WillReturnRows(mock.NewRows(query.NewPendingTransactionQuery().Fields)) // which is escrow expiration process default: mockRows := sqlmock.NewRows(query.NewEscrowTransactionQuery().Fields) @@ -935,11 +938,7 @@ func (*mockPushBlockCoinbaseLotteryWinnersSuccess) CoinbaseLotteryWinners(blocks return []string{}, nil } -func (*mockPushBlockBlocksmithServiceSuccess) RewardBlocksmithAccountAddresses( - blocksmithAccountAddresses []string, - totalReward, blockTimestamp int64, - height uint32, -) error { +func (*mockPushBlockBlocksmithServiceSuccess) RewardBlocksmithAccountAddresses([]string, int64, int64, uint32) error { return nil } @@ -1056,9 +1055,15 @@ func TestBlockService_PushBlock(t *testing.T) { CoinbaseService: &mockPushBlockCoinbaseLotteryWinnersSuccess{}, BlocksmithService: &mockPushBlockBlocksmithServiceSuccess{}, TransactionCoreService: NewTransactionCoreService( + log.New(), &mockQueryExecutorSuccess{}, + &transaction.TypeSwitcher{ + Executor: &mockQueryExecutorSuccess{}, + }, + &transaction.Util{}, query.NewTransactionQuery(&chaintype.MainChain{}), query.NewEscrowTransactionQuery(), + query.NewPendingTransactionQuery(), ), PublishedReceiptService: &mockPushBlockPublishedReceiptServiceSuccess{}, }, @@ -1116,9 +1121,13 @@ func TestBlockService_PushBlock(t *testing.T) { CoinbaseService: &mockPushBlockCoinbaseLotteryWinnersSuccess{}, BlocksmithService: &mockPushBlockBlocksmithServiceSuccess{}, TransactionCoreService: NewTransactionCoreService( + log.New(), &mockQueryExecutorSuccess{}, + &transaction.TypeSwitcher{Executor: &mockQueryExecutorSuccess{}}, + &transaction.Util{}, query.NewTransactionQuery(&chaintype.MainChain{}), query.NewEscrowTransactionQuery(), + query.NewPendingTransactionQuery(), ), PublishedReceiptService: &mockPushBlockPublishedReceiptServiceSuccess{}, }, @@ -1176,9 +1185,15 @@ func TestBlockService_PushBlock(t *testing.T) { CoinbaseService: &mockPushBlockCoinbaseLotteryWinnersSuccess{}, BlocksmithService: &mockPushBlockBlocksmithServiceSuccess{}, TransactionCoreService: NewTransactionCoreService( + log.New(), &mockQueryExecutorSuccess{}, + &transaction.TypeSwitcher{ + Executor: &mockQueryExecutorSuccess{}, + }, + &transaction.Util{}, query.NewTransactionQuery(&chaintype.MainChain{}), query.NewEscrowTransactionQuery(), + query.NewPendingTransactionQuery(), ), PublishedReceiptService: &mockPushBlockPublishedReceiptServiceSuccess{}, }, @@ -1236,9 +1251,15 @@ func TestBlockService_PushBlock(t *testing.T) { CoinbaseService: &mockPushBlockCoinbaseLotteryWinnersSuccess{}, BlocksmithService: &mockPushBlockBlocksmithServiceSuccess{}, TransactionCoreService: NewTransactionCoreService( + log.New(), &mockQueryExecutorSuccess{}, + &transaction.TypeSwitcher{ + Executor: &mockQueryExecutorSuccess{}, + }, + &transaction.Util{}, query.NewTransactionQuery(&chaintype.MainChain{}), query.NewEscrowTransactionQuery(), + query.NewPendingTransactionQuery(), ), PublishedReceiptService: &mockPushBlockPublishedReceiptServiceSuccess{}, }, @@ -1900,9 +1921,15 @@ func TestBlockService_AddGenesis(t *testing.T) { BlockPoolService: &mockBlockPoolServiceNoDuplicate{}, Logger: log.New(), TransactionCoreService: NewTransactionCoreService( + log.New(), &mockQueryExecutorSuccess{}, + &transaction.TypeSwitcher{ + Executor: &mockQueryExecutorSuccess{}, + }, + &transaction.Util{}, query.NewTransactionQuery(&chaintype.MainChain{}), query.NewEscrowTransactionQuery(), + query.NewPendingTransactionQuery(), ), PublishedReceiptService: &mockAddGenesisPublishedReceiptServiceSuccess{}, }, @@ -4201,6 +4228,9 @@ func (*mockExecutorBlockPopSuccess) ExecuteSelect(qStr string, tx bool, args ... "transaction_index FROM \"transaction\" WHERE block_id = ? ORDER BY transaction_index ASC": mock.ExpectQuery(regexp.QuoteMeta(qStr)).WillReturnRows( sqlmock.NewRows(transactionQ.Fields)) + case "SELECT sender_address, transaction_hash, transaction_bytes, status, block_height, latest FROM pending_transaction " + + "WHERE (block_height+?) = ? AND status = ? AND latest = ?": + mock.ExpectQuery(regexp.QuoteMeta(qStr)).WillReturnRows(mock.NewRows(query.NewPendingTransactionQuery().Fields)) } return db.Query(qStr) diff --git a/core/service/mempoolCoreService_test.go b/core/service/mempoolCoreService_test.go index 063220b2c..ecf9745c3 100644 --- a/core/service/mempoolCoreService_test.go +++ b/core/service/mempoolCoreService_test.go @@ -471,9 +471,13 @@ func TestMempoolService_DeleteExpiredMempoolTransactions(t *testing.T) { Executor: &mockQueryExecutorDeleteExpiredMempoolTransactions{}, }, TransactionCoreService: NewTransactionCoreService( + log.New(), &mockQueryExecutorDeleteExpiredMempoolTransactions{}, + nil, + nil, query.NewTransactionQuery(&chaintype.MainChain{}), nil, + nil, ), }, wantErr: false, @@ -980,9 +984,13 @@ func TestMempoolService_ReceivedTransaction(t *testing.T) { ActionTypeSwitcher: &mockActionTypeSwitcherSuccess{}, Observer: observer.NewObserver(), TransactionCoreService: NewTransactionCoreService( + log.New(), &mockQueryExecutorDeleteExpiredMempoolTransactions{}, + nil, + nil, query.NewTransactionQuery(&chaintype.MainChain{}), nil, + nil, ), }, args: args{}, diff --git a/core/service/mempoolServiceUtil_test.go b/core/service/mempoolServiceUtil_test.go index 8b90d4894..a6f03904c 100644 --- a/core/service/mempoolServiceUtil_test.go +++ b/core/service/mempoolServiceUtil_test.go @@ -8,6 +8,8 @@ import ( "strings" "testing" + "github.com/sirupsen/logrus" + "github.com/DATA-DOG/go-sqlmock" "github.com/zoobc/zoobc-core/common/chaintype" "github.com/zoobc/zoobc-core/common/model" @@ -245,9 +247,12 @@ func TestMempoolService_ValidateMempoolTransaction(t *testing.T) { AccountBalanceQuery: query.NewAccountBalanceQuery(), TransactionQuery: query.NewTransactionQuery(&chaintype.MainChain{}), TransactionCoreService: NewTransactionCoreService( - &mockExecutorValidateMempoolTransactionSuccessNoRow{}, + logrus.New(), &mockExecutorValidateMempoolTransactionSuccessNoRow{}, + nil, + nil, query.NewTransactionQuery(&chaintype.MainChain{}), nil, + nil, ), }, args: args{ diff --git a/core/service/transactionCoreService.go b/core/service/transactionCoreService.go index 256b1d4ee..d4c7792f9 100644 --- a/core/service/transactionCoreService.go +++ b/core/service/transactionCoreService.go @@ -3,6 +3,7 @@ package service import ( "database/sql" + "github.com/sirupsen/logrus" "github.com/zoobc/zoobc-core/common/blocker" "github.com/zoobc/zoobc-core/common/model" "github.com/zoobc/zoobc-core/common/query" @@ -18,24 +19,37 @@ type ( UndoApplyUnconfirmedTransaction(txAction transaction.TypeAction) error ApplyConfirmedTransaction(txAction transaction.TypeAction, blockTimestamp int64) error ExpiringEscrowTransactions(blockHeight uint32, useTX bool) error + ExpiringPendingTransactions(blockHeight uint32, useTX bool) error } TransactionCoreService struct { - TransactionQuery query.TransactionQueryInterface - EscrowTransactionQuery query.EscrowTransactionQueryInterface - QueryExecutor query.ExecutorInterface + Log *logrus.Logger + QueryExecutor query.ExecutorInterface + TypeActionSwitcher transaction.TypeActionSwitcher + TransactionUtil transaction.UtilInterface + TransactionQuery query.TransactionQueryInterface + EscrowTransactionQuery query.EscrowTransactionQueryInterface + PendingTransactionQuery query.PendingTransactionQueryInterface } ) func NewTransactionCoreService( + log *logrus.Logger, queryExecutor query.ExecutorInterface, + typeActionSwitcher transaction.TypeActionSwitcher, + transactionUtil transaction.UtilInterface, transactionQuery query.TransactionQueryInterface, escrowTransactionQuery query.EscrowTransactionQueryInterface, + pendingTransactionQuery query.PendingTransactionQueryInterface, ) TransactionCoreServiceInterface { return &TransactionCoreService{ - TransactionQuery: transactionQuery, - EscrowTransactionQuery: escrowTransactionQuery, - QueryExecutor: queryExecutor, + Log: log, + QueryExecutor: queryExecutor, + TypeActionSwitcher: typeActionSwitcher, + TransactionUtil: transactionUtil, + TransactionQuery: transactionQuery, + EscrowTransactionQuery: escrowTransactionQuery, + PendingTransactionQuery: pendingTransactionQuery, } } @@ -86,21 +100,28 @@ func (tg *TransactionCoreService) ExpiringEscrowTransactions(blockHeight uint32, err error ) - escrowQ, escrowArgs := tg.EscrowTransactionQuery.GetEscrowTransactions(map[string]interface{}{ - "timeout": blockHeight, - "status": model.EscrowStatus_Pending, - "latest": 1, - }) - rows, err = tg.QueryExecutor.ExecuteSelect(escrowQ, useTX, escrowArgs...) - if err != nil { - return err - } - defer rows.Close() + err = func() error { + escrowQ, escrowArgs := tg.EscrowTransactionQuery.GetEscrowTransactions(map[string]interface{}{ + "timeout": blockHeight, + "status": model.EscrowStatus_Pending, + "latest": 1, + }) + rows, err = tg.QueryExecutor.ExecuteSelect(escrowQ, useTX, escrowArgs...) + if err != nil { + return err + } + defer rows.Close() - escrows, err = tg.EscrowTransactionQuery.BuildModels(rows) + escrows, err = tg.EscrowTransactionQuery.BuildModels(rows) + if err != nil { + return err + } + return nil + }() if err != nil { return err } + if len(escrows) > 0 { if !useTX { err = tg.QueryExecutor.BeginTx() @@ -119,19 +140,120 @@ func (tg *TransactionCoreService) ExpiringEscrowTransactions(blockHeight uint32, nEscrow.Status = model.EscrowStatus_Expired q := tg.EscrowTransactionQuery.InsertEscrowTransaction(escrow) err = tg.QueryExecutor.ExecuteTransactions(q) + if err != nil { + break + } + } + + if !useTX { + /* + Check the latest error is not nil, otherwise need to aborting the whole query transactions safety with rollBack. + And automatically unlock mutex + */ + if err != nil { + if rollbackErr := tg.QueryExecutor.RollbackTx(); rollbackErr != nil { + tg.Log.Errorf("Rollback fail: %s", rollbackErr.Error()) + } + return err + } + + err = tg.QueryExecutor.CommitTx() + if err != nil { + if rollbackErr := tg.QueryExecutor.RollbackTx(); rollbackErr != nil { + tg.Log.Errorf("Rollback fail: %s", rollbackErr.Error()) + } + return err + } + } + } + return nil +} + +// ExpiringPendingTransactions will set status to be expired caused by current block height +func (tg *TransactionCoreService) ExpiringPendingTransactions(blockHeight uint32, useTX bool) error { + var ( + pendingTransactions []*model.PendingTransaction + innerTransaction *model.Transaction + typeAction transaction.TypeAction + rows *sql.Rows + err error + ) + + err = func() error { + qy, qArgs := tg.PendingTransactionQuery.GetPendingTransactionsExpireByHeight(blockHeight) + rows, err = tg.QueryExecutor.ExecuteSelect(qy, useTX, qArgs...) + if err != nil { + return err + } + defer rows.Close() + + pendingTransactions, err = tg.PendingTransactionQuery.BuildModel(pendingTransactions, rows) + if err != nil { + return err + } + return nil + }() + if err != nil { + return err + } + + if len(pendingTransactions) > 0 { + if !useTX { + err = tg.QueryExecutor.BeginTx() if err != nil { return err } } + for _, pendingTransaction := range pendingTransactions { + + /** + SET PendingTransaction + 1. block height = current block height + 2. status = expired + */ + nPendingTransaction := pendingTransaction + nPendingTransaction.BlockHeight = blockHeight + nPendingTransaction.Status = model.PendingTransactionStatus_PendingTransactionExpired + q := tg.PendingTransactionQuery.InsertPendingTransaction(nPendingTransaction) + err = tg.QueryExecutor.ExecuteTransactions(q) + if err != nil { + break + } + // Do UndoApplyConfirmed + innerTransaction, err = tg.TransactionUtil.ParseTransactionBytes(nPendingTransaction.GetTransactionBytes(), false) + if err != nil { + break + } + typeAction, err = tg.TypeActionSwitcher.GetTransactionType(innerTransaction) + if err != nil { + break + } + err = typeAction.UndoApplyUnconfirmed() + if err != nil { + break + } + } if !useTX { + /* + Check the latest error is not nil, otherwise need to aborting the whole query transactions safety with rollBack. + And automatically unlock mutex + */ + if err != nil { + if rollbackErr := tg.QueryExecutor.RollbackTx(); rollbackErr != nil { + tg.Log.Errorf("Rollback fail: %s", rollbackErr.Error()) + } + return err + } err = tg.QueryExecutor.CommitTx() if err != nil { - if errRollback := tg.QueryExecutor.RollbackTx(); errRollback != nil { - return err + if rollbackErr := tg.QueryExecutor.RollbackTx(); rollbackErr != nil { + tg.Log.Errorf("Rollback fail: %s", rollbackErr.Error()) } + return err } } + return err } return nil } diff --git a/main.go b/main.go index f01a3988b..961d0b0d6 100644 --- a/main.go +++ b/main.go @@ -211,9 +211,15 @@ func init() { ) transactionCoreServiceIns = service.NewTransactionCoreService( + loggerCoreService, queryExecutor, + &transaction.TypeSwitcher{ + Executor: queryExecutor, + }, + &transaction.Util{}, query.NewTransactionQuery(mainchain), query.NewEscrowTransactionQuery(), + query.NewPendingTransactionQuery(), ) defaultSignatureType = crypto.NewEd25519Signature() @@ -602,9 +608,15 @@ func startMainchain() { Logger: loggerCoreService, TransactionUtil: transactionUtil, TransactionCorService: service.NewTransactionCoreService( + loggerCoreService, queryExecutor, + &transaction.TypeSwitcher{ + Executor: queryExecutor, + }, + &transaction.Util{}, query.NewTransactionQuery(mainchain), query.NewEscrowTransactionQuery(), + query.NewPendingTransactionQuery(), ), } mainchainSynchronizer = blockchainsync.NewBlockchainSyncService( @@ -691,9 +703,15 @@ func startSpinechain() { Logger: loggerCoreService, TransactionUtil: transactionUtil, TransactionCorService: service.NewTransactionCoreService( + loggerCoreService, queryExecutor, + &transaction.TypeSwitcher{ + Executor: queryExecutor, + }, + &transaction.Util{}, query.NewTransactionQuery(mainchain), query.NewEscrowTransactionQuery(), + query.NewPendingTransactionQuery(), ), } spinechainSynchronizer = blockchainsync.NewBlockchainSyncService(