Skip to content

829 download escrow transaction #834

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
May 14, 2020
15 changes: 15 additions & 0 deletions common/query/escrowTransactionQuery.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ type (
InsertEscrowTransaction(escrow *model.Escrow) [][]interface{}
GetLatestEscrowTransactionByID(int64) (string, []interface{})
GetEscrowTransactions(fields map[string]interface{}) (string, []interface{})
GetEscrowTransactionsByTransactionIdsAndStatus(
transactionIds []string, status model.EscrowStatus,
) string
ExpiringEscrowTransactions(blockHeight uint32) (string, []interface{})
ExtractModel(*model.Escrow) []interface{}
BuildModels(*sql.Rows) ([]*model.Escrow, error)
Expand Down Expand Up @@ -123,6 +126,18 @@ func (et *EscrowTransactionQuery) ExpiringEscrowTransactions(blockHeight uint32)
}
}

func (et *EscrowTransactionQuery) GetEscrowTransactionsByTransactionIdsAndStatus(
transactionIds []string, status model.EscrowStatus,
) string {
return fmt.Sprintf(
"SELECT %s FROM %s WHERE id IN (%s) AND status = %d",
strings.Join(et.Fields, ", "),
et.getTableName(),
strings.Join(transactionIds, ", "),
status,
)
}

// ExtractModel will extract values of escrow as []interface{}
func (et *EscrowTransactionQuery) ExtractModel(escrow *model.Escrow) []interface{} {
return []interface{}{
Expand Down
13 changes: 13 additions & 0 deletions common/query/escrowTransactionQuery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package query

import (
"database/sql"
"fmt"
"reflect"
"sort"
"strings"
Expand Down Expand Up @@ -534,3 +535,15 @@ func TestEscrowTransactionQuery_TrimDataBeforeSnapshot(t *testing.T) {
})
}
}

func TestEscrowTransactionQuery_GetEscrowTransactionsByTransactionIdsAndStatus(t *testing.T) {
t.Run("GetPendingEscrowTransactionsByTransactionIds", func(t *testing.T) {
escrowQuery := NewEscrowTransactionQuery()
query := escrowQuery.GetEscrowTransactionsByTransactionIdsAndStatus([]string{"1", "2"}, model.EscrowStatus_Pending)
expect := fmt.Sprintf("SELECT id, sender_address, recipient_address, approver_address, amount, commission, timeout, status, "+
"block_height, latest, instruction FROM escrow_transaction WHERE id IN (1, 2) AND status = %d", model.EscrowStatus_Pending)
if query != expect {
t.Errorf("expect: %v\ngot: %v\n", expect, query)
}
})
}
9 changes: 6 additions & 3 deletions core/service/blockMainService.go
Original file line number Diff line number Diff line change
Expand Up @@ -611,10 +611,12 @@ func (bs *BlockService) PushBlock(previousBlock, block *model.Block, broadcast,
bs.Logger.Error(rollbackErr.Error())
}
if broadcast {
// create copy of the block to avoid reference update on block pool
blockToBroadcast := *block
// add transactionIDs and remove transaction before broadcast
block.TransactionIDs = transactionIDs
block.Transactions = []*model.Transaction{}
bs.Observer.Notify(observer.BroadcastBlock, block, bs.Chaintype)
blockToBroadcast.TransactionIDs = transactionIDs
blockToBroadcast.Transactions = []*model.Transaction{}
bs.Observer.Notify(observer.BroadcastBlock, blockToBroadcast, bs.Chaintype)
}
return nil
}
Expand Down Expand Up @@ -664,6 +666,7 @@ func (bs *BlockService) ScanBlockPool() error {
)
}
err = bs.PushBlock(previousBlock, block, true, true)

if err != nil {
bs.Logger.Warnf("ScanBlockPool:PushBlockFail: %v\n", blocker.NewBlocker(blocker.PushMainBlockErr, err.Error(), block, previousBlock))
return blocker.NewBlocker(
Expand Down
51 changes: 44 additions & 7 deletions core/service/transactionCoreService.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package service

import (
"database/sql"
"strconv"

"github.com/sirupsen/logrus"
"github.com/zoobc/zoobc-core/common/blocker"
Expand Down Expand Up @@ -76,18 +77,54 @@ func (tg *TransactionCoreService) GetTransactionsByIds(transactionIds []int64) (

// GetTransactionsByBlockID get transactions of the block
func (tg *TransactionCoreService) GetTransactionsByBlockID(blockID int64) ([]*model.Transaction, error) {
var transactions []*model.Transaction
var (
transactions []*model.Transaction
escrows []*model.Escrow
txIdsStr []string
err error
)

// get transaction of the block
transactionQ, transactionArg := tg.TransactionQuery.GetTransactionsByBlockID(blockID)
rows, err := tg.QueryExecutor.ExecuteSelect(transactionQ, false, transactionArg...)

transactions, err = func() ([]*model.Transaction, error) {
transactionQ, transactionArg := tg.TransactionQuery.GetTransactionsByBlockID(blockID)
rows, err := tg.QueryExecutor.ExecuteSelect(transactionQ, false, transactionArg...)
if err != nil {
return nil, blocker.NewBlocker(blocker.DBErr, err.Error())
}
defer rows.Close()
return tg.TransactionQuery.BuildModel(transactions, rows)
}()
if err != nil {
return nil, blocker.NewBlocker(blocker.DBErr, err.Error())
}
defer rows.Close()

return tg.TransactionQuery.BuildModel(transactions, rows)
// fetch escrow if exist
for _, tx := range transactions {
txIdsStr = append(txIdsStr, "'"+strconv.FormatInt(tx.ID, 10)+"'")
}
if len(txIdsStr) > 0 {
escrows, err = func() ([]*model.Escrow, error) {
escrowQ := tg.EscrowTransactionQuery.GetEscrowTransactionsByTransactionIdsAndStatus(
txIdsStr, model.EscrowStatus_Pending,
)
rows, err := tg.QueryExecutor.ExecuteSelect(escrowQ, false)
if err != nil {
return nil, err
}
defer rows.Close()
return tg.EscrowTransactionQuery.BuildModels(rows)
}()
if err != nil {
return nil, blocker.NewBlocker(blocker.DBErr, err.Error())
}
for _, escrow := range escrows {
for _, tx := range transactions {
if tx.ID == escrow.ID {
tx.Escrow = escrow
}
}
}
}
return transactions, nil
}

// ExpiringEscrowTransactions push an observer event that is ExpiringEscrowTransactions,
Expand Down
58 changes: 51 additions & 7 deletions core/service/transactionCoreService_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ type (
mockGetTransactionsByBlockIDTransactionQueryBuildSuccess struct {
query.TransactionQuery
}
mockGetTransactionsByBlockIDEscrowTransactionQueryBuildSuccessOne struct {
query.EscrowTransactionQuery
}
mockGetTransactionsByBlockIDEscrowTransactionQueryBuildSuccessEmpty struct {
query.EscrowTransactionQuery
}
// GetTransactionsByBlockID mocks
)

Expand All @@ -57,6 +63,18 @@ var (
TransactionHash: make([]byte, 32),
},
}
mockGetTransactionsByBlockIDResultWithEscrow = []*model.Transaction{
{
TransactionHash: make([]byte, 32),
Escrow: mockGetTransactionByBlockIDEscrowTransactionResultOne[0],
},
}
mockGetTransactionByBlockIDEscrowTransactionResultOne = []*model.Escrow{
{
ID: 0,
},
}
mockGetTransactionByBlockIDEscrowTransactionResultEmpty = make([]*model.Escrow, 0)
)

func (*mockGetTransactionsByIdsExecutorFail) ExecuteSelect(query string, tx bool, args ...interface{}) (*sql.Rows, error) {
Expand Down Expand Up @@ -102,6 +120,16 @@ func (*mockGetTransactionsByBlockIDTransactionQueryBuildFail) BuildModel(
return nil, errors.New("mockedError")
}

func (*mockGetTransactionsByBlockIDEscrowTransactionQueryBuildSuccessOne) BuildModels(
rows *sql.Rows) ([]*model.Escrow, error) {
return mockGetTransactionByBlockIDEscrowTransactionResultOne, nil
}

func (*mockGetTransactionsByBlockIDEscrowTransactionQueryBuildSuccessEmpty) BuildModels(
rows *sql.Rows) ([]*model.Escrow, error) {
return mockGetTransactionByBlockIDEscrowTransactionResultEmpty, nil
}

func (*mockGetTransactionsByBlockIDTransactionQueryBuildSuccess) BuildModel(
txs []*model.Transaction, rows *sql.Rows) ([]*model.Transaction, error) {
return mockGetTransactionsByBlockIDResult, nil
Expand Down Expand Up @@ -179,8 +207,9 @@ func TestTransactionCoreService_GetTransactionsByIds(t *testing.T) {

func TestTransactionCoreService_GetTransactionsByBlockID(t *testing.T) {
type fields struct {
TransactionQuery query.TransactionQueryInterface
QueryExecutor query.ExecutorInterface
TransactionQuery query.TransactionQueryInterface
EscrowTransactionQuery query.EscrowTransactionQueryInterface
QueryExecutor query.ExecutorInterface
}
type args struct {
blockID int64
Expand Down Expand Up @@ -217,10 +246,24 @@ func TestTransactionCoreService_GetTransactionsByBlockID(t *testing.T) {
wantErr: true,
},
{
name: "GetTransactionsByBlockID-BuildModel-Success",
name: "GetTransactionsByBlockID-BuildModel-Success-EscrowOneResult",
fields: fields{
TransactionQuery: &mockGetTransactionsByBlockIDTransactionQueryBuildSuccess{},
QueryExecutor: &mockGetTransactionsByBlockIDExecutorSuccess{},
TransactionQuery: &mockGetTransactionsByBlockIDTransactionQueryBuildSuccess{},
EscrowTransactionQuery: &mockGetTransactionsByBlockIDEscrowTransactionQueryBuildSuccessOne{},
QueryExecutor: &mockGetTransactionsByBlockIDExecutorSuccess{},
},
args: args{
blockID: 1,
},
want: mockGetTransactionsByBlockIDResultWithEscrow,
wantErr: false,
},
{
name: "GetTransactionsByBlockID-BuildModel-Success-EscrowEmptyResult",
fields: fields{
TransactionQuery: &mockGetTransactionsByBlockIDTransactionQueryBuildSuccess{},
EscrowTransactionQuery: &mockGetTransactionsByBlockIDEscrowTransactionQueryBuildSuccessEmpty{},
QueryExecutor: &mockGetTransactionsByBlockIDExecutorSuccess{},
},
args: args{
blockID: 1,
Expand All @@ -232,8 +275,9 @@ func TestTransactionCoreService_GetTransactionsByBlockID(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tg := &TransactionCoreService{
TransactionQuery: tt.fields.TransactionQuery,
QueryExecutor: tt.fields.QueryExecutor,
TransactionQuery: tt.fields.TransactionQuery,
EscrowTransactionQuery: tt.fields.EscrowTransactionQuery,
QueryExecutor: tt.fields.QueryExecutor,
}
got, err := tg.GetTransactionsByBlockID(tt.args.blockID)
if (err != nil) != tt.wantErr {
Expand Down
17 changes: 12 additions & 5 deletions core/smith/strategy/blocksmithStrategyMain.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,10 +226,10 @@ func (bss *BlocksmithStrategyMain) CanPersistBlock(
previousBlock *model.Block,
) error {
var (
err error
ct = &chaintype.MainChain{}
currentTime = time.Now().Unix()
remainder, prevRoundBegin, prevRoundExpired int64
err error
ct = &chaintype.MainChain{}
currentTime = time.Now().Unix()
remainder, prevRoundBegin, prevRoundExpired, prevRound2Begin, prevRound2Expired int64
)
// always return true for the first block | keeping in mind genesis block's timestamps is far behind, let fork processor
// handle to get highest cum-diff block
Expand Down Expand Up @@ -260,13 +260,20 @@ func (bss *BlocksmithStrategyMain) CanPersistBlock(
prevRoundExpired = prevRoundBegin + ct.GetBlocksmithBlockCreationTime() +
ct.GetBlocksmithNetworkTolerance()
}
if timeRound > 1 { // handle small network, go one more round
prevRound2Start := nearestRoundBeginning - 2*timeForOneRound
prevRound2Begin = prevRound2Start + blocksmithIndex*ct.GetBlocksmithTimeGap()
prevRound2Expired = prevRound2Begin + ct.GetBlocksmithBlockCreationTime() +
ct.GetBlocksmithNetworkTolerance()
}
// calculate current round begin and expiry time
allowedBeginTime := blocksmithIndex*ct.GetBlocksmithTimeGap() + nearestRoundBeginning
expiredTime := allowedBeginTime + ct.GetBlocksmithBlockCreationTime() +
ct.GetBlocksmithNetworkTolerance()
// check if current time is in {(expire-timeGap) < x < (expire)} in either previous round or current round
if (currentTime > (expiredTime-ct.GetBlocksmithTimeGap()) && currentTime <= expiredTime) ||
(currentTime > (prevRoundExpired-ct.GetBlocksmithTimeGap()) && currentTime <= prevRoundExpired) {
(currentTime > (prevRoundExpired-ct.GetBlocksmithTimeGap()) && currentTime <= prevRoundExpired) ||
(currentTime > (prevRound2Expired-ct.GetBlocksmithTimeGap()) && currentTime <= prevRound2Expired) {
return nil
}
return blocker.NewBlocker(blocker.BlockErr, "CannotPersistBlock")
Expand Down