Repository: coinbase/rosetta-cli
Pull request #78 (2020-07-25 19:09:40)

[BUG] Parse Operation Success in CoinStorage
Related PR: #68 

### Fixes
Only modify `CoinStorage` if operation is `successful`.


Patch:
diff --git a/internal/storage/coin_storage.go b/internal/storage/coin_storage.go
index c0af020..4dce701 100644
--- a/internal/storage/coin_storage.go
+++ b/internal/storage/coin_storage.go
@@ -18,6 +18,7 @@ import (
 	"context"
 	"fmt"
 
+	"github.com/coinbase/rosetta-sdk-go/asserter"
 	"github.com/coinbase/rosetta-sdk-go/types"
 )
 
@@ -39,14 +40,18 @@ var _ BlockWorker = (*CoinStorage)(nil)
 // UTXOs.
 type CoinStorage struct {
 	db Database
+
+	asserter *asserter.Asserter
 }
 
 // NewCoinStorage returns a new CoinStorage.
 func NewCoinStorage(
 	db Database,
+	asserter *asserter.Asserter,
 ) *CoinStorage {
 	return &CoinStorage{
-		db: db,
+		db:       db,
+		asserter: asserter,
 	}
 }
 
@@ -245,6 +250,15 @@ func (c *CoinStorage) AddingBlock(
 ) (CommitWorker, error) {
 	for _, txn := range block.Transactions {
 		for _, operation := range txn.Operations {
+			success, err := c.asserter.OperationSuccessful(operation)
+			if err != nil {
+				return nil, fmt.Errorf("%w: unable to parse operation success", err)
+			}
+
+			if !success {
+				continue
+			}
+
 			if operation.Amount == nil {
 				continue
 			}
@@ -270,6 +284,15 @@ func (c *CoinStorage) RemovingBlock(
 ) (CommitWorker, error) {
 	for _, txn := range block.Transactions {
 		for _, operation := range txn.Operations {
+			success, err := c.asserter.OperationSuccessful(operation)
+			if err != nil {
+				return nil, fmt.Errorf("%w: unable to parse operation success", err)
+			}
+
+			if !success {
+				continue
+			}
+
 			if operation.Amount == nil {
 				continue
 			}


Test patch:
diff --git a/internal/storage/coin_storage_test.go b/internal/storage/coin_storage_test.go
index aef2102..8bf5eb1 100644
--- a/internal/storage/coin_storage_test.go
+++ b/internal/storage/coin_storage_test.go
@@ -20,6 +20,7 @@ import (
 
 	"github.com/coinbase/rosetta-cli/internal/utils"
 
+	"github.com/coinbase/rosetta-sdk-go/asserter"
 	"github.com/coinbase/rosetta-sdk-go/types"
 	"github.com/stretchr/testify/assert"
 )
@@ -69,12 +70,16 @@ var (
 		},
 	}
 
+	successStatus = "success"
+	failureStatus = "failure"
+
 	coinBlock = &types.Block{
 		Transactions: []*types.Transaction{
 			{
 				Operations: []*types.Operation{
 					{
 						Account: account,
+						Status:  successStatus,
 						Amount: &types.Amount{
 							Value: "10",
 						},
@@ -84,6 +89,7 @@ var (
 					},
 					{
 						Account: account2,
+						Status:  successStatus,
 						Amount: &types.Amount{
 							Value: "15",
 						},
@@ -91,6 +97,16 @@ var (
 							coinSpent: "coin2",
 						},
 					},
+					{
+						Account: account2,
+						Status:  failureStatus,
+						Amount: &types.Amount{
+							Value: "20",
+						},
+						Metadata: map[string]interface{}{
+							coinSpent: "coin2",
+						},
+					},
 				},
 			},
 		},
@@ -102,6 +118,7 @@ var (
 				Operations: []*types.Operation{
 					{
 						Account: account,
+						Status:  successStatus,
 						Amount: &types.Amount{
 							Value: "-10",
 						},
@@ -120,6 +137,7 @@ var (
 				Operations: []*types.Operation{
 					{
 						Account: account3,
+						Status:  successStatus,
 						Amount: &types.Amount{
 							Value: "4",
 						},
@@ -133,6 +151,7 @@ var (
 				Operations: []*types.Operation{
 					{
 						Account: account3,
+						Status:  successStatus,
 						Amount: &types.Amount{
 							Value: "6",
 						},
@@ -142,6 +161,20 @@ var (
 					},
 				},
 			},
+			{
+				Operations: []*types.Operation{
+					{
+						Account: account3,
+						Status:  failureStatus,
+						Amount: &types.Amount{
+							Value: "12",
+						},
+						Metadata: map[string]interface{}{
+							coinCreated: "coin5",
+						},
+					},
+				},
+			},
 		},
 	}
 )
@@ -157,7 +190,32 @@ func TestCoinStorage(t *testing.T) {
 	assert.NoError(t, err)
 	defer database.Close(ctx)
 
-	c := NewCoinStorage(database)
+	a, err := asserter.NewClientWithOptions(
+		&types.NetworkIdentifier{
+			Blockchain: "bitcoin",
+			Network:    "mainnet",
+		},
+		&types.BlockIdentifier{
+			Hash:  "block 0",
+			Index: 0,
+		},
+		[]string{"Transfer"},
+		[]*types.OperationStatus{
+			{
+				Status:     successStatus,
+				Successful: true,
+			},
+			{
+				Status:     failureStatus,
+				Successful: false,
+			},
+		},
+		[]*types.Error{},
+	)
+	assert.NoError(t, err)
+	assert.NotNil(t, a)
+
+	c := NewCoinStorage(database, a)
 
 	t.Run("get coins of unset account", func(t *testing.T) {
 		coins, err := c.GetCoins(ctx, account)