Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add FindRelatedTransactions Function for Block Storage #290

Merged
merged 14 commits into from
Feb 19, 2021
22 changes: 22 additions & 0 deletions asserter/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,10 @@ func (a *Asserter) Transaction(
// any of the related transactions contain invalid types, invalid network identifiers,
// invalid transaction identifiers, or a direction not defined by the enum.
func (a *Asserter) RelatedTransactions(relatedTransactions []*types.RelatedTransaction) error {
if dup := DuplicateRelatedTransaction(relatedTransactions); dup != nil {
return fmt.Errorf("%w: %v", ErrDuplicateRelatedTransaction, dup)
}

for i, relatedTransaction := range relatedTransactions {
if relatedTransaction.NetworkIdentifier != nil {
if err := NetworkIdentifier(relatedTransaction.NetworkIdentifier); err != nil {
Expand Down Expand Up @@ -401,6 +405,24 @@ func (a *Asserter) RelatedTransactions(relatedTransactions []*types.RelatedTrans
return nil
}

// DuplicateRelatedTransaction returns nil if no duplicates are found in the array and
// returns the first duplicated item found otherwise.
func DuplicateRelatedTransaction(
items []*types.RelatedTransaction,
) *types.RelatedTransaction {
seen := map[string]struct{}{}
for _, item := range items {
key := types.Hash(item)
if _, ok := seen[key]; ok {
return item
}

seen[key] = struct{}{}
}

return nil
}

// Direction returns an error if the value passed is not types.Forward or types.Backward
func (a *Asserter) Direction(direction types.Direction) error {
if direction != types.Forward &&
Expand Down
62 changes: 62 additions & 0 deletions asserter/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,59 @@ func TestBlock(t *testing.T) {
},
},
}
duplicateRelatedTransactions := &types.Transaction{
TransactionIdentifier: &types.TransactionIdentifier{
Hash: "blah",
},
Operations: []*types.Operation{
{
OperationIdentifier: &types.OperationIdentifier{
Index: int64(0),
},
Type: "PAYMENT",
Status: types.String("SUCCESS"),
Account: validAccount,
Amount: validAmount,
},
{
OperationIdentifier: &types.OperationIdentifier{
Index: int64(1),
},
RelatedOperations: []*types.OperationIdentifier{
{
Index: int64(0),
},
},
Type: "PAYMENT",
Status: types.String("SUCCESS"),
Account: validAccount,
Amount: validAmount,
},
},
RelatedTransactions: []*types.RelatedTransaction{
{
NetworkIdentifier: &types.NetworkIdentifier{
Blockchain: "hello",
Network: "world",
},
TransactionIdentifier: &types.TransactionIdentifier{
Hash: "blah",
},
Direction: types.Forward,
},
{
NetworkIdentifier: &types.NetworkIdentifier{
Blockchain: "hello",
Network: "world",
},
TransactionIdentifier: &types.TransactionIdentifier{
Hash: "blah",
},
Direction: types.Forward,
},
},
}

var tests = map[string]struct {
block *types.Block
genesisIndex int64
Expand Down Expand Up @@ -908,6 +961,15 @@ func TestBlock(t *testing.T) {
},
err: ErrInvalidDirection,
},
"duplicate related transaction": {
block: &types.Block{
BlockIdentifier: validBlockIdentifier,
ParentBlockIdentifier: validParentBlockIdentifier,
Timestamp: MinUnixEpoch + 1,
Transactions: []*types.Transaction{duplicateRelatedTransactions},
},
err: ErrDuplicateRelatedTransaction,
},
}

for name, test := range tests {
Expand Down
6 changes: 5 additions & 1 deletion asserter/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ var (
ErrBlockIndexPrecedesParentBlockIndex = errors.New(
"BlockIdentifier.Index <= ParentBlockIdentifier.Index",
)
ErrInvalidDirection = errors.New("invalid direction (must be 'forward' or 'backward')")
ErrInvalidDirection = errors.New(
"invalid direction (must be 'forward' or 'backward')",
)
ErrDuplicateRelatedTransaction = errors.New("duplicate related transaction")

BlockErrs = []error{
ErrAmountValueMissing,
Expand Down Expand Up @@ -127,6 +130,7 @@ var (
ErrBlockHashEqualsParentBlockHash,
ErrBlockIndexPrecedesParentBlockIndex,
ErrInvalidDirection,
ErrDuplicateRelatedTransaction,
}
)

Expand Down
4 changes: 4 additions & 0 deletions storage/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@ var (
ErrNothingToPrune = errors.New("nothing to prune")
ErrPruningFailed = errors.New("pruning failed")
ErrCannotPruneTransaction = errors.New("cannot prune transaction")
ErrCannotStoreBackwardRelation = errors.New("cannot store backward relation")
ErrCannotRemoveBackwardRelation = errors.New("cannot remove backward relation")

BlockStorageErrs = []error{
ErrHeadBlockNotFound,
Expand Down Expand Up @@ -438,6 +440,8 @@ var (
ErrNothingToPrune,
ErrPruningFailed,
ErrCannotPruneTransaction,
ErrCannotStoreBackwardRelation,
ErrCannotRemoveBackwardRelation,
}
)

Expand Down
Loading