Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
zistvan-public
StreamChain Prototype
Commits
c8efd6a9
Commit
c8efd6a9
authored
Oct 27, 2017
by
Artem Barger
Committed by
Gerrit Code Review
Oct 27, 2017
Browse files
Merge "[FAB-6669] forbid Tx with same ID as other in blck"
parents
c9097f58
69fd2b18
Changes
8
Hide whitespace changes
Inline
Side-by-side
common/capabilities/application.go
View file @
c8efd6a9
...
...
@@ -52,3 +52,9 @@ func (ap *ApplicationProvider) HasCapability(capability string) bool {
func
(
ap
*
ApplicationProvider
)
LifecycleViaConfig
()
bool
{
return
ap
.
v11
}
// ForbidDuplicateTXIdInBlock specifies whether two transactions with the same TXId are permitted
// in the same block or whether we mark the second one as TxValidationCode_DUPLICATE_TXID
func
(
ap
*
ApplicationProvider
)
ForbidDuplicateTXIdInBlock
()
bool
{
return
ap
.
v11
}
common/channelconfig/api.go
View file @
c8efd6a9
...
...
@@ -116,6 +116,10 @@ type ChannelCapabilities interface {
type
ApplicationCapabilities
interface
{
// Supported returns an error if there are unknown capabilities in this channel which are required
Supported
()
error
// ForbidDuplicateTXIdInBlock specifies whether two transactions with the same TXId are permitted
// in the same block or whether we mark the second one as TxValidationCode_DUPLICATE_TXID
ForbidDuplicateTXIdInBlock
()
bool
}
// OrdererCapabilities defines the capabilities for the orderer portion of a channel
...
...
common/ledger/testutil/test_helper.go
View file @
c8efd6a9
...
...
@@ -110,7 +110,7 @@ func ConstructBlockWithTxid(t *testing.T, blockNum uint64, previousHash []byte,
}
envs
=
append
(
envs
,
env
)
}
return
n
ewBlock
(
envs
,
blockNum
,
previousHash
)
return
N
ewBlock
(
envs
,
blockNum
,
previousHash
)
}
// ConstructBlock constructs a single block
...
...
@@ -123,7 +123,7 @@ func ConstructBlock(t *testing.T, blockNum uint64, previousHash []byte, simulati
}
envs
=
append
(
envs
,
env
)
}
return
n
ewBlock
(
envs
,
blockNum
,
previousHash
)
return
N
ewBlock
(
envs
,
blockNum
,
previousHash
)
}
//ConstructTestBlock constructs a single block with random contents
...
...
@@ -155,7 +155,7 @@ func ConstructBytesProposalResponsePayload(version string, simulationResults []b
return
ptestutils
.
ConstructBytesProposalResponsePayload
(
util
.
GetTestChainID
(),
ccid
,
nil
,
simulationResults
)
}
func
n
ewBlock
(
env
[]
*
common
.
Envelope
,
blockNum
uint64
,
previousHash
[]
byte
)
*
common
.
Block
{
func
N
ewBlock
(
env
[]
*
common
.
Envelope
,
blockNum
uint64
,
previousHash
[]
byte
)
*
common
.
Block
{
block
:=
common
.
NewBlock
(
blockNum
,
previousHash
)
for
i
:=
0
;
i
<
len
(
env
);
i
++
{
txEnvBytes
,
_
:=
proto
.
Marshal
(
env
[
i
])
...
...
common/mocks/config/application.go
0 → 100644
View file @
c8efd6a9
/*
Copyright IBM Corp. 2017 All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package
config
type
MockApplicationCapabilities
struct
{
SupportedRv
error
ForbidDuplicateTXIdInBlockRv
bool
}
func
(
mac
*
MockApplicationCapabilities
)
Supported
()
error
{
return
mac
.
SupportedRv
}
func
(
mac
*
MockApplicationCapabilities
)
ForbidDuplicateTXIdInBlock
()
bool
{
return
mac
.
ForbidDuplicateTXIdInBlockRv
}
core/committer/txvalidator/txvalidator_test.go
View file @
c8efd6a9
...
...
@@ -22,6 +22,7 @@ import (
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/configtx/test"
"github.com/hyperledger/fabric/common/ledger/testutil"
"github.com/hyperledger/fabric/common/mocks/config"
util2
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/common/sysccprovider"
ledger2
"github.com/hyperledger/fabric/core/ledger"
...
...
@@ -60,7 +61,7 @@ func testValidationWithNTXes(t *testing.T, ledger ledger2.PeerLedger, gbHash []b
vcs
:=
struct
{
*
mocktxvalidator
.
Support
*
semaphore
.
Weighted
}{
&
mocktxvalidator
.
Support
{
LedgerVal
:
ledger
},
semaphore
.
NewWeighted
(
10
)}
}{
&
mocktxvalidator
.
Support
{
LedgerVal
:
ledger
,
ACVal
:
&
config
.
MockApplicationCapabilities
{}
},
semaphore
.
NewWeighted
(
10
)}
tValidator
:=
&
txValidator
{
vcs
,
mockVsccValidator
}
bcInfo
,
_
:=
ledger
.
GetBlockchainInfo
()
...
...
@@ -103,6 +104,89 @@ func testValidationWithNTXes(t *testing.T, ledger ledger2.PeerLedger, gbHash []b
*/
}
func
TestDetectTXIdDuplicates
(
t
*
testing
.
T
)
{
txids
:=
[]
string
{
""
,
"1"
,
"2"
,
"3"
,
""
,
"2"
,
""
}
txsfltr
:=
ledgerUtil
.
NewTxValidationFlags
(
len
(
txids
))
markTXIdDuplicates
(
txids
,
txsfltr
)
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
0
,
peer
.
TxValidationCode_VALID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
1
,
peer
.
TxValidationCode_VALID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
2
,
peer
.
TxValidationCode_VALID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
3
,
peer
.
TxValidationCode_VALID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
4
,
peer
.
TxValidationCode_VALID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
5
,
peer
.
TxValidationCode_DUPLICATE_TXID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
6
,
peer
.
TxValidationCode_VALID
))
txids
=
[]
string
{
""
,
"1"
,
"2"
,
"3"
,
""
,
"21"
,
""
}
txsfltr
=
ledgerUtil
.
NewTxValidationFlags
(
len
(
txids
))
markTXIdDuplicates
(
txids
,
txsfltr
)
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
0
,
peer
.
TxValidationCode_VALID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
1
,
peer
.
TxValidationCode_VALID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
2
,
peer
.
TxValidationCode_VALID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
3
,
peer
.
TxValidationCode_VALID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
4
,
peer
.
TxValidationCode_VALID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
5
,
peer
.
TxValidationCode_VALID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
6
,
peer
.
TxValidationCode_VALID
))
}
func
TestBlockValidationDuplicateTXId
(
t
*
testing
.
T
)
{
viper
.
Set
(
"peer.fileSystemPath"
,
"/tmp/fabric/txvalidatortest"
)
ledgermgmt
.
InitializeTestEnv
()
defer
ledgermgmt
.
CleanupTestEnv
()
gb
,
_
:=
test
.
MakeGenesisBlock
(
"TestLedger"
)
gbHash
:=
gb
.
Header
.
Hash
()
ledger
,
_
:=
ledgermgmt
.
CreateLedger
(
gb
)
defer
ledger
.
Close
()
txid
:=
util2
.
GenerateUUID
()
simulator
,
_
:=
ledger
.
NewTxSimulator
(
txid
)
simulator
.
SetState
(
"ns1"
,
"key1"
,
[]
byte
(
"value1"
))
simulator
.
SetState
(
"ns1"
,
"key2"
,
[]
byte
(
"value2"
))
simulator
.
SetState
(
"ns1"
,
"key3"
,
[]
byte
(
"value3"
))
simulator
.
Done
()
simRes
,
_
:=
simulator
.
GetTxSimulationResults
()
pubSimulationResBytes
,
_
:=
simRes
.
GetPubSimulationBytes
()
_
,
err
:=
testutil
.
ConstructBytesProposalResponsePayload
(
"v1"
,
pubSimulationResBytes
)
if
err
!=
nil
{
t
.
Fatalf
(
"Could not construct ProposalResponsePayload bytes, err: %s"
,
err
)
}
mockVsccValidator
:=
&
validator
.
MockVsccValidator
{}
acv
:=
&
config
.
MockApplicationCapabilities
{}
vcs
:=
struct
{
*
mocktxvalidator
.
Support
*
semaphore
.
Weighted
}{
&
mocktxvalidator
.
Support
{
LedgerVal
:
ledger
,
ACVal
:
acv
},
semaphore
.
NewWeighted
(
10
)}
tValidator
:=
&
txValidator
{
vcs
,
mockVsccValidator
}
bcInfo
,
_
:=
ledger
.
GetBlockchainInfo
()
testutil
.
AssertEquals
(
t
,
bcInfo
,
&
common
.
BlockchainInfo
{
Height
:
1
,
CurrentBlockHash
:
gbHash
,
PreviousBlockHash
:
nil
})
envs
:=
[]
*
common
.
Envelope
{}
env
,
_
,
err
:=
testutil
.
ConstructTransaction
(
t
,
pubSimulationResBytes
,
""
,
true
)
envs
=
append
(
envs
,
env
)
envs
=
append
(
envs
,
env
)
block
:=
testutil
.
NewBlock
(
envs
,
1
,
gbHash
)
tValidator
.
Validate
(
block
)
txsfltr
:=
util
.
TxValidationFlags
(
block
.
Metadata
.
Metadata
[
common
.
BlockMetadataIndex_TRANSACTIONS_FILTER
])
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
0
,
peer
.
TxValidationCode_VALID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
1
,
peer
.
TxValidationCode_VALID
))
acv
.
ForbidDuplicateTXIdInBlockRv
=
true
tValidator
.
Validate
(
block
)
txsfltr
=
util
.
TxValidationFlags
(
block
.
Metadata
.
Metadata
[
common
.
BlockMetadataIndex_TRANSACTIONS_FILTER
])
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
0
,
peer
.
TxValidationCode_VALID
))
assert
.
True
(
t
,
txsfltr
.
IsSetTo
(
1
,
peer
.
TxValidationCode_DUPLICATE_TXID
))
}
func
TestBlockValidation
(
t
*
testing
.
T
)
{
viper
.
Set
(
"peer.fileSystemPath"
,
"/tmp/fabric/txvalidatortest"
)
ledgermgmt
.
InitializeTestEnv
()
...
...
@@ -160,7 +244,7 @@ func TestNewTxValidator_DuplicateTransactions(t *testing.T) {
vcs
:=
struct
{
*
mocktxvalidator
.
Support
*
semaphore
.
Weighted
}{
&
mocktxvalidator
.
Support
{
LedgerVal
:
ledger
},
semaphore
.
NewWeighted
(
10
)}
}{
&
mocktxvalidator
.
Support
{
LedgerVal
:
ledger
,
ACVal
:
&
config
.
MockApplicationCapabilities
{}
},
semaphore
.
NewWeighted
(
10
)}
tValidator
:=
&
txValidator
{
vcs
,
&
validator
.
MockVsccValidator
{}}
// Create simple endorsement transaction
...
...
core/committer/txvalidator/validator.go
View file @
c8efd6a9
...
...
@@ -29,6 +29,7 @@ import (
"github.com/op/go-logging"
"github.com/hyperledger/fabric/common/cauthdsl"
"github.com/hyperledger/fabric/common/channelconfig"
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
)
...
...
@@ -52,6 +53,9 @@ type Support interface {
// GetMSPIDs returns the IDs for the application MSPs
// that have been defined in the channel
GetMSPIDs
(
cid
string
)
[]
string
// Capabilities defines the capabilities for the application portion of this channel
Capabilities
()
channelconfig
.
ApplicationCapabilities
}
//Validator interface which defines API to validate block transactions
...
...
@@ -138,6 +142,7 @@ type blockValidationResult struct {
txsChaincodeName
*
sysccprovider
.
ChaincodeInstance
txsUpgradedChaincode
*
sysccprovider
.
ChaincodeInstance
err
error
txid
string
}
// NewTxValidator creates new transactions validator
...
...
@@ -187,6 +192,8 @@ func (v *txValidator) Validate(block *common.Block) error {
txsChaincodeNames
:=
make
(
map
[
int
]
*
sysccprovider
.
ChaincodeInstance
)
// upgradedChaincodes records all the chaincodes that are upgraded in a block
txsUpgradedChaincodes
:=
make
(
map
[
int
]
*
sysccprovider
.
ChaincodeInstance
)
// array of txids
txidArray
:=
make
([]
string
,
len
(
block
.
Data
.
Data
))
results
:=
make
(
chan
*
blockValidationResult
)
go
func
()
{
...
...
@@ -240,6 +247,7 @@ func (v *txValidator) Validate(block *common.Block) error {
if
res
.
txsUpgradedChaincode
!=
nil
{
txsUpgradedChaincodes
[
res
.
tIdx
]
=
res
.
txsUpgradedChaincode
}
txidArray
[
res
.
tIdx
]
=
res
.
txid
}
}
}
...
...
@@ -251,6 +259,12 @@ func (v *txValidator) Validate(block *common.Block) error {
return
err
}
// if we operate with this capability, we mark invalid any transaction that has a txid
// which is equal to that of a previous tx in this block
if
v
.
support
.
Capabilities
()
.
ForbidDuplicateTXIdInBlock
()
{
markTXIdDuplicates
(
txidArray
,
txsfltr
)
}
// if we're here, all workers have completed validation and
// no error was reported; we set the tx filter and return
// success
...
...
@@ -265,11 +279,30 @@ func (v *txValidator) Validate(block *common.Block) error {
return
nil
}
func
markTXIdDuplicates
(
txids
[]
string
,
txsfltr
ledgerUtil
.
TxValidationFlags
)
{
txidMap
:=
make
(
map
[
string
]
struct
{})
for
id
,
txid
:=
range
txids
{
if
txid
==
""
{
continue
}
_
,
in
:=
txidMap
[
txid
]
if
in
{
logger
.
Error
(
"Duplicate txid"
,
txid
,
"found, skipping"
)
txsfltr
.
SetFlag
(
id
,
peer
.
TxValidationCode_DUPLICATE_TXID
)
}
else
{
txidMap
[
txid
]
=
struct
{}{}
}
}
}
func
validateTx
(
req
*
blockValidationRequest
,
results
chan
<-
*
blockValidationResult
)
{
block
:=
req
.
block
d
:=
req
.
d
tIdx
:=
req
.
tIdx
v
:=
req
.
v
txID
:=
""
if
d
==
nil
{
results
<-
&
blockValidationResult
{
...
...
@@ -332,7 +365,7 @@ func validateTx(req *blockValidationRequest, results chan<- *blockValidationResu
if
common
.
HeaderType
(
chdr
.
Type
)
==
common
.
HeaderType_ENDORSER_TRANSACTION
{
// Check duplicate transactions
txID
:
=
chdr
.
TxId
txID
=
chdr
.
TxId
if
_
,
err
:=
v
.
support
.
Ledger
()
.
GetTransactionByID
(
txID
);
err
==
nil
{
logger
.
Error
(
"Duplicate transaction found, "
,
txID
,
", skipping"
)
results
<-
&
blockValidationResult
{
...
...
@@ -346,7 +379,6 @@ func validateTx(req *blockValidationRequest, results chan<- *blockValidationResu
logger
.
Debug
(
"Validating transaction vscc tx validate"
)
err
,
cde
:=
v
.
vscc
.
VSCCValidateTx
(
payload
,
d
,
env
)
if
err
!=
nil
{
txID
:=
txID
logger
.
Errorf
(
"VSCCValidateTx for transaction txId = %s returned error %s"
,
txID
,
err
)
switch
err
.
(
type
)
{
case
*
VSCCExecutionFailureError
:
...
...
@@ -430,6 +462,7 @@ func validateTx(req *blockValidationRequest, results chan<- *blockValidationResu
txsChaincodeName
:
txsChaincodeName
,
txsUpgradedChaincode
:
txsUpgradedChaincode
,
validationCode
:
peer
.
TxValidationCode_VALID
,
txid
:
txID
,
}
return
}
else
{
...
...
core/committer/txvalidator/validator_test.go
View file @
c8efd6a9
...
...
@@ -26,6 +26,7 @@ import (
ctxt
"github.com/hyperledger/fabric/common/configtx/test"
ledger2
"github.com/hyperledger/fabric/common/ledger"
"github.com/hyperledger/fabric/common/ledger/testutil"
mockconfig
"github.com/hyperledger/fabric/common/mocks/config"
"github.com/hyperledger/fabric/common/mocks/scc"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/chaincode/shim"
...
...
@@ -36,6 +37,7 @@ import (
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
lutils
"github.com/hyperledger/fabric/core/ledger/util"
"github.com/hyperledger/fabric/core/mocks/ccprovider"
mocktxvalidator
"github.com/hyperledger/fabric/core/mocks/txvalidator"
"github.com/hyperledger/fabric/msp"
"github.com/hyperledger/fabric/msp/mgmt"
"github.com/hyperledger/fabric/msp/mgmt/testtools"
...
...
@@ -61,9 +63,9 @@ func setupLedgerAndValidator(t *testing.T) (ledger.PeerLedger, Validator) {
theLedger
,
err
:=
ledgermgmt
.
CreateLedger
(
gb
)
assert
.
NoError
(
t
,
err
)
vcs
:=
struct
{
*
mockSupport
*
mock
txvalidator
.
Support
*
semaphore
.
Weighted
}{
&
mock
Support
{
l
:
theLedger
},
semaphore
.
NewWeighted
(
10
)}
}{
&
mock
txvalidator
.
Support
{
LedgerVal
:
theLedger
,
ACVal
:
&
mockconfig
.
MockApplicationCapabilities
{}
},
semaphore
.
NewWeighted
(
10
)}
theValidator
:=
NewTxValidator
(
vcs
)
return
theLedger
,
theValidator
...
...
@@ -142,26 +144,6 @@ func putCCInfo(theLedger ledger.PeerLedger, ccname string, policy []byte, t *tes
putCCInfoWithVSCCAndVer
(
theLedger
,
ccname
,
"vscc"
,
ccVersion
,
policy
,
t
)
}
type
mockSupport
struct
{
l
ledger
.
PeerLedger
}
func
(
m
*
mockSupport
)
Ledger
()
ledger
.
PeerLedger
{
return
m
.
l
}
func
(
m
*
mockSupport
)
MSPManager
()
msp
.
MSPManager
{
return
mgmt
.
GetManagerForChain
(
util
.
GetTestChainID
())
}
func
(
m
*
mockSupport
)
Apply
(
configtx
*
common
.
ConfigEnvelope
)
error
{
return
nil
}
func
(
m
*
mockSupport
)
GetMSPIDs
(
cid
string
)
[]
string
{
return
[]
string
{
"DEFAULT"
}
}
func
assertInvalid
(
block
*
common
.
Block
,
t
*
testing
.
T
,
code
peer
.
TxValidationCode
)
{
txsFilter
:=
lutils
.
TxValidationFlags
(
block
.
Metadata
.
Metadata
[
common
.
BlockMetadataIndex_TRANSACTIONS_FILTER
])
assert
.
True
(
t
,
txsFilter
.
IsInvalid
(
0
))
...
...
@@ -568,9 +550,9 @@ func (exec *mockQueryExecutor) Done() {
func
TestLedgerIsNoAvailable
(
t
*
testing
.
T
)
{
theLedger
:=
new
(
mockLedger
)
vcs
:=
struct
{
*
mockSupport
*
mock
txvalidator
.
Support
*
semaphore
.
Weighted
}{
&
mock
Support
{
l
:
theLedger
},
semaphore
.
NewWeighted
(
10
)}
}{
&
mock
txvalidator
.
Support
{
LedgerVal
:
theLedger
,
ACVal
:
&
mockconfig
.
MockApplicationCapabilities
{}
},
semaphore
.
NewWeighted
(
10
)}
validator
:=
NewTxValidator
(
vcs
)
ccID
:=
"mycc"
...
...
@@ -596,9 +578,9 @@ func TestLedgerIsNoAvailable(t *testing.T) {
func
TestValidationInvalidEndorsing
(
t
*
testing
.
T
)
{
theLedger
:=
new
(
mockLedger
)
vcs
:=
struct
{
*
mockSupport
*
mock
txvalidator
.
Support
*
semaphore
.
Weighted
}{
&
mock
Support
{
l
:
theLedger
},
semaphore
.
NewWeighted
(
10
)}
}{
&
mock
txvalidator
.
Support
{
LedgerVal
:
theLedger
,
ACVal
:
&
mockconfig
.
MockApplicationCapabilities
{}
},
semaphore
.
NewWeighted
(
10
)}
validator
:=
NewTxValidator
(
vcs
)
ccID
:=
"mycc"
...
...
core/mocks/txvalidator/support.go
View file @
c8efd6a9
...
...
@@ -17,6 +17,7 @@ limitations under the License.
package
support
import
(
"github.com/hyperledger/fabric/common/channelconfig"
mockpolicies
"github.com/hyperledger/fabric/common/mocks/policies"
"github.com/hyperledger/fabric/common/policies"
"github.com/hyperledger/fabric/core/ledger"
...
...
@@ -28,6 +29,11 @@ type Support struct {
LedgerVal
ledger
.
PeerLedger
MSPManagerVal
msp
.
MSPManager
ApplyVal
error
ACVal
channelconfig
.
ApplicationCapabilities
}
func
(
ms
*
Support
)
Capabilities
()
channelconfig
.
ApplicationCapabilities
{
return
ms
.
ACVal
}
// Ledger returns LedgerVal
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment