Skip to content

Commit 97066b5

Browse files
committed
[FAB-1038] Rework committer to be more general
While interating over block transaction and running validation, need also to check the uniqueness of txid. This commit adds check to query ledger for transactions to verify that there is no duplicates. Change-Id: Ieea4c9e61d0a320d7842ba3ab21f6d50e583beba Signed-off-by: Artem Barger <[email protected]>
1 parent f0c43f7 commit 97066b5

File tree

2 files changed

+81
-7
lines changed

2 files changed

+81
-7
lines changed

core/committer/txvalidator/txvalidator_test.go

+65
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@ package txvalidator
1919
import (
2020
"testing"
2121

22+
"github.com/golang/protobuf/proto"
2223
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
2324
"github.com/hyperledger/fabric/core/ledger/testutil"
2425
"github.com/hyperledger/fabric/core/ledger/util"
26+
util2 "github.com/hyperledger/fabric/core/util"
2527
"github.com/hyperledger/fabric/protos/common"
2628
pb "github.com/hyperledger/fabric/protos/peer"
29+
"github.com/hyperledger/fabric/protos/utils"
2730
"github.com/spf13/viper"
2831
"github.com/stretchr/testify/assert"
2932
)
@@ -65,3 +68,65 @@ func TestKVLedgerBlockStorage(t *testing.T) {
6568
assert.True(t, !txsfltr.IsSet(uint(1)))
6669
assert.True(t, !txsfltr.IsSet(uint(2)))
6770
}
71+
72+
func TestNewTxValidator_DuplicateTransactions(t *testing.T) {
73+
viper.Set("peer.fileSystemPath", "/tmp/fabric/txvalidatortest")
74+
ledgermgmt.InitializeTestEnv()
75+
defer ledgermgmt.CleanupTestEnv()
76+
ledger, _ := ledgermgmt.CreateLedger("TestLedger")
77+
defer ledger.Close()
78+
79+
validator := &txValidator{ledger, &mockVsccValidator{}}
80+
81+
// Create simeple endorsement transaction
82+
payload := &common.Payload{
83+
Header: &common.Header{
84+
ChainHeader: &common.ChainHeader{
85+
TxID: "simple_txID", // Fake txID
86+
Type: int32(common.HeaderType_ENDORSER_TRANSACTION),
87+
ChainID: util2.GetTestChainID(),
88+
},
89+
},
90+
Data: []byte("test"),
91+
}
92+
93+
payloadBytes, err := proto.Marshal(payload)
94+
95+
// Check marshaling didn't fail
96+
assert.NoError(t, err)
97+
98+
// Envelope the payload
99+
envelope := &common.Envelope{
100+
Payload: payloadBytes,
101+
}
102+
103+
envelopeBytes, err := proto.Marshal(envelope)
104+
105+
// Check marshaling didn't fail
106+
assert.NoError(t, err)
107+
108+
block := &common.Block{
109+
Data: &common.BlockData{
110+
// Enconde transactions
111+
Data: [][]byte{envelopeBytes},
112+
},
113+
}
114+
115+
block.Header = &common.BlockHeader{
116+
Number: 1,
117+
DataHash: block.Data.Hash(),
118+
}
119+
120+
// Initialize metadata
121+
utils.InitBlockMetadata(block)
122+
// Commit block to the ledger
123+
ledger.Commit(block)
124+
125+
// Validation should invalidate transaction,
126+
// because it's already committed
127+
validator.Validate(block)
128+
129+
txsfltr := util.NewFilterBitArrayFromBytes(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
130+
131+
assert.True(t, txsfltr.IsSet(0))
132+
}

core/committer/txvalidator/validator.go

+16-7
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,12 @@ func (v *txValidator) Validate(block *common.Block) {
7777
defer logger.Debug("END Block Validation")
7878
txsfltr := ledgerUtil.NewFilterBitArray(uint(len(block.Data.Data)))
7979
for tIdx, d := range block.Data.Data {
80+
// Start by marking transaction as invalid, before
81+
// doing any validation checks.
82+
txsfltr.Set(uint(tIdx))
8083
if d != nil {
8184
if env, err := utils.GetEnvelopeFromBlock(d); err != nil {
8285
logger.Warningf("Error getting tx from block(%s)", err)
83-
txsfltr.Set(uint(tIdx))
8486
} else if env != nil {
8587
// validate the transaction: here we check that the transaction
8688
// is properly formed, properly signed and that the security
@@ -90,25 +92,32 @@ func (v *txValidator) Validate(block *common.Block) {
9092
logger.Debug("Validating transaction peer.ValidateTransaction()")
9193
if payload, _, err := peer.ValidateTransaction(env); err != nil {
9294
logger.Errorf("Invalid transaction with index %d, error %s", tIdx, err)
93-
txsfltr.Set(uint(tIdx))
9495
} else {
96+
// Check duplicate transactions
97+
txID := payload.Header.ChainHeader.TxID
98+
if _, err := v.ledger.GetTransactionByID(txID); err == nil {
99+
logger.Warning("Duplicate transaction found, ", txID, ", skipping")
100+
continue
101+
}
102+
95103
//the payload is used to get headers
96104
logger.Debug("Validating transaction vscc tx validate")
97105
if err = v.vscc.VSCCValidateTx(payload, d); err != nil {
98-
txID := payload.Header.ChainHeader.TxID
106+
txID := txID
99107
logger.Errorf("VSCCValidateTx for transaction txId = %s returned error %s", txID, err)
100-
txsfltr.Set(uint(tIdx))
101108
continue
102109
}
103110

104111
if _, err := proto.Marshal(env); err != nil {
105-
logger.Warningf("Cannot marshal transactoins %s", err)
106-
txsfltr.Set(uint(tIdx))
112+
logger.Warningf("Cannot marshal transaction due to %s", err)
113+
continue
107114
}
115+
// Succeeded to pass down here, transaction is valid,
116+
// just unset the filter bit array flag.
117+
txsfltr.Unset(uint(tIdx))
108118
}
109119
} else {
110120
logger.Warning("Nil tx from block")
111-
txsfltr.Set(uint(tIdx))
112121
}
113122
}
114123
}

0 commit comments

Comments
 (0)