Commit c8efd6a9 authored by Artem Barger's avatar Artem Barger Committed by Gerrit Code Review
Browse files

Merge "[FAB-6669] forbid Tx with same ID as other in blck"

parents c9097f58 69fd2b18
...@@ -52,3 +52,9 @@ func (ap *ApplicationProvider) HasCapability(capability string) bool { ...@@ -52,3 +52,9 @@ func (ap *ApplicationProvider) HasCapability(capability string) bool {
func (ap *ApplicationProvider) LifecycleViaConfig() bool { func (ap *ApplicationProvider) LifecycleViaConfig() bool {
return ap.v11 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
}
...@@ -116,6 +116,10 @@ type ChannelCapabilities interface { ...@@ -116,6 +116,10 @@ type ChannelCapabilities interface {
type ApplicationCapabilities interface { type ApplicationCapabilities interface {
// Supported returns an error if there are unknown capabilities in this channel which are required // Supported returns an error if there are unknown capabilities in this channel which are required
Supported() error 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 // OrdererCapabilities defines the capabilities for the orderer portion of a channel
......
...@@ -110,7 +110,7 @@ func ConstructBlockWithTxid(t *testing.T, blockNum uint64, previousHash []byte, ...@@ -110,7 +110,7 @@ func ConstructBlockWithTxid(t *testing.T, blockNum uint64, previousHash []byte,
} }
envs = append(envs, env) envs = append(envs, env)
} }
return newBlock(envs, blockNum, previousHash) return NewBlock(envs, blockNum, previousHash)
} }
// ConstructBlock constructs a single block // ConstructBlock constructs a single block
...@@ -123,7 +123,7 @@ func ConstructBlock(t *testing.T, blockNum uint64, previousHash []byte, simulati ...@@ -123,7 +123,7 @@ func ConstructBlock(t *testing.T, blockNum uint64, previousHash []byte, simulati
} }
envs = append(envs, env) envs = append(envs, env)
} }
return newBlock(envs, blockNum, previousHash) return NewBlock(envs, blockNum, previousHash)
} }
//ConstructTestBlock constructs a single block with random contents //ConstructTestBlock constructs a single block with random contents
...@@ -155,7 +155,7 @@ func ConstructBytesProposalResponsePayload(version string, simulationResults []b ...@@ -155,7 +155,7 @@ func ConstructBytesProposalResponsePayload(version string, simulationResults []b
return ptestutils.ConstructBytesProposalResponsePayload(util.GetTestChainID(), ccid, nil, simulationResults) return ptestutils.ConstructBytesProposalResponsePayload(util.GetTestChainID(), ccid, nil, simulationResults)
} }
func newBlock(env []*common.Envelope, blockNum uint64, previousHash []byte) *common.Block { func NewBlock(env []*common.Envelope, blockNum uint64, previousHash []byte) *common.Block {
block := common.NewBlock(blockNum, previousHash) block := common.NewBlock(blockNum, previousHash)
for i := 0; i < len(env); i++ { for i := 0; i < len(env); i++ {
txEnvBytes, _ := proto.Marshal(env[i]) txEnvBytes, _ := proto.Marshal(env[i])
......
/*
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
}
...@@ -22,6 +22,7 @@ import ( ...@@ -22,6 +22,7 @@ import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/configtx/test" "github.com/hyperledger/fabric/common/configtx/test"
"github.com/hyperledger/fabric/common/ledger/testutil" "github.com/hyperledger/fabric/common/ledger/testutil"
"github.com/hyperledger/fabric/common/mocks/config"
util2 "github.com/hyperledger/fabric/common/util" util2 "github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/common/sysccprovider" "github.com/hyperledger/fabric/core/common/sysccprovider"
ledger2 "github.com/hyperledger/fabric/core/ledger" ledger2 "github.com/hyperledger/fabric/core/ledger"
...@@ -60,7 +61,7 @@ func testValidationWithNTXes(t *testing.T, ledger ledger2.PeerLedger, gbHash []b ...@@ -60,7 +61,7 @@ func testValidationWithNTXes(t *testing.T, ledger ledger2.PeerLedger, gbHash []b
vcs := struct { vcs := struct {
*mocktxvalidator.Support *mocktxvalidator.Support
*semaphore.Weighted *semaphore.Weighted
}{&mocktxvalidator.Support{LedgerVal: ledger}, semaphore.NewWeighted(10)} }{&mocktxvalidator.Support{LedgerVal: ledger, ACVal: &config.MockApplicationCapabilities{}}, semaphore.NewWeighted(10)}
tValidator := &txValidator{vcs, mockVsccValidator} tValidator := &txValidator{vcs, mockVsccValidator}
bcInfo, _ := ledger.GetBlockchainInfo() bcInfo, _ := ledger.GetBlockchainInfo()
...@@ -103,6 +104,89 @@ func testValidationWithNTXes(t *testing.T, ledger ledger2.PeerLedger, gbHash []b ...@@ -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) { func TestBlockValidation(t *testing.T) {
viper.Set("peer.fileSystemPath", "/tmp/fabric/txvalidatortest") viper.Set("peer.fileSystemPath", "/tmp/fabric/txvalidatortest")
ledgermgmt.InitializeTestEnv() ledgermgmt.InitializeTestEnv()
...@@ -160,7 +244,7 @@ func TestNewTxValidator_DuplicateTransactions(t *testing.T) { ...@@ -160,7 +244,7 @@ func TestNewTxValidator_DuplicateTransactions(t *testing.T) {
vcs := struct { vcs := struct {
*mocktxvalidator.Support *mocktxvalidator.Support
*semaphore.Weighted *semaphore.Weighted
}{&mocktxvalidator.Support{LedgerVal: ledger}, semaphore.NewWeighted(10)} }{&mocktxvalidator.Support{LedgerVal: ledger, ACVal: &config.MockApplicationCapabilities{}}, semaphore.NewWeighted(10)}
tValidator := &txValidator{vcs, &validator.MockVsccValidator{}} tValidator := &txValidator{vcs, &validator.MockVsccValidator{}}
// Create simple endorsement transaction // Create simple endorsement transaction
......
...@@ -29,6 +29,7 @@ import ( ...@@ -29,6 +29,7 @@ import (
"github.com/op/go-logging" "github.com/op/go-logging"
"github.com/hyperledger/fabric/common/cauthdsl" "github.com/hyperledger/fabric/common/cauthdsl"
"github.com/hyperledger/fabric/common/channelconfig"
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil" "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
) )
...@@ -52,6 +53,9 @@ type Support interface { ...@@ -52,6 +53,9 @@ type Support interface {
// GetMSPIDs returns the IDs for the application MSPs // GetMSPIDs returns the IDs for the application MSPs
// that have been defined in the channel // that have been defined in the channel
GetMSPIDs(cid string) []string 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 //Validator interface which defines API to validate block transactions
...@@ -138,6 +142,7 @@ type blockValidationResult struct { ...@@ -138,6 +142,7 @@ type blockValidationResult struct {
txsChaincodeName *sysccprovider.ChaincodeInstance txsChaincodeName *sysccprovider.ChaincodeInstance
txsUpgradedChaincode *sysccprovider.ChaincodeInstance txsUpgradedChaincode *sysccprovider.ChaincodeInstance
err error err error
txid string
} }
// NewTxValidator creates new transactions validator // NewTxValidator creates new transactions validator
...@@ -187,6 +192,8 @@ func (v *txValidator) Validate(block *common.Block) error { ...@@ -187,6 +192,8 @@ func (v *txValidator) Validate(block *common.Block) error {
txsChaincodeNames := make(map[int]*sysccprovider.ChaincodeInstance) txsChaincodeNames := make(map[int]*sysccprovider.ChaincodeInstance)
// upgradedChaincodes records all the chaincodes that are upgraded in a block // upgradedChaincodes records all the chaincodes that are upgraded in a block
txsUpgradedChaincodes := make(map[int]*sysccprovider.ChaincodeInstance) txsUpgradedChaincodes := make(map[int]*sysccprovider.ChaincodeInstance)
// array of txids
txidArray := make([]string, len(block.Data.Data))
results := make(chan *blockValidationResult) results := make(chan *blockValidationResult)
go func() { go func() {
...@@ -240,6 +247,7 @@ func (v *txValidator) Validate(block *common.Block) error { ...@@ -240,6 +247,7 @@ func (v *txValidator) Validate(block *common.Block) error {
if res.txsUpgradedChaincode != nil { if res.txsUpgradedChaincode != nil {
txsUpgradedChaincodes[res.tIdx] = res.txsUpgradedChaincode txsUpgradedChaincodes[res.tIdx] = res.txsUpgradedChaincode
} }
txidArray[res.tIdx] = res.txid
} }
} }
} }
...@@ -251,6 +259,12 @@ func (v *txValidator) Validate(block *common.Block) error { ...@@ -251,6 +259,12 @@ func (v *txValidator) Validate(block *common.Block) error {
return err 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 // if we're here, all workers have completed validation and
// no error was reported; we set the tx filter and return // no error was reported; we set the tx filter and return
// success // success
...@@ -265,11 +279,30 @@ func (v *txValidator) Validate(block *common.Block) error { ...@@ -265,11 +279,30 @@ func (v *txValidator) Validate(block *common.Block) error {
return nil 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) { func validateTx(req *blockValidationRequest, results chan<- *blockValidationResult) {
block := req.block block := req.block
d := req.d d := req.d
tIdx := req.tIdx tIdx := req.tIdx
v := req.v v := req.v
txID := ""
if d == nil { if d == nil {
results <- &blockValidationResult{ results <- &blockValidationResult{
...@@ -332,7 +365,7 @@ func validateTx(req *blockValidationRequest, results chan<- *blockValidationResu ...@@ -332,7 +365,7 @@ func validateTx(req *blockValidationRequest, results chan<- *blockValidationResu
if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION { if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION {
// Check duplicate transactions // Check duplicate transactions
txID := chdr.TxId txID = chdr.TxId
if _, err := v.support.Ledger().GetTransactionByID(txID); err == nil { if _, err := v.support.Ledger().GetTransactionByID(txID); err == nil {
logger.Error("Duplicate transaction found, ", txID, ", skipping") logger.Error("Duplicate transaction found, ", txID, ", skipping")
results <- &blockValidationResult{ results <- &blockValidationResult{
...@@ -346,7 +379,6 @@ func validateTx(req *blockValidationRequest, results chan<- *blockValidationResu ...@@ -346,7 +379,6 @@ func validateTx(req *blockValidationRequest, results chan<- *blockValidationResu
logger.Debug("Validating transaction vscc tx validate") logger.Debug("Validating transaction vscc tx validate")
err, cde := v.vscc.VSCCValidateTx(payload, d, env) err, cde := v.vscc.VSCCValidateTx(payload, d, env)
if err != nil { if err != nil {
txID := txID
logger.Errorf("VSCCValidateTx for transaction txId = %s returned error %s", txID, err) logger.Errorf("VSCCValidateTx for transaction txId = %s returned error %s", txID, err)
switch err.(type) { switch err.(type) {
case *VSCCExecutionFailureError: case *VSCCExecutionFailureError:
...@@ -430,6 +462,7 @@ func validateTx(req *blockValidationRequest, results chan<- *blockValidationResu ...@@ -430,6 +462,7 @@ func validateTx(req *blockValidationRequest, results chan<- *blockValidationResu
txsChaincodeName: txsChaincodeName, txsChaincodeName: txsChaincodeName,
txsUpgradedChaincode: txsUpgradedChaincode, txsUpgradedChaincode: txsUpgradedChaincode,
validationCode: peer.TxValidationCode_VALID, validationCode: peer.TxValidationCode_VALID,
txid: txID,
} }
return return
} else { } else {
......
...@@ -26,6 +26,7 @@ import ( ...@@ -26,6 +26,7 @@ import (
ctxt "github.com/hyperledger/fabric/common/configtx/test" ctxt "github.com/hyperledger/fabric/common/configtx/test"
ledger2 "github.com/hyperledger/fabric/common/ledger" ledger2 "github.com/hyperledger/fabric/common/ledger"
"github.com/hyperledger/fabric/common/ledger/testutil" "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/mocks/scc"
"github.com/hyperledger/fabric/common/util" "github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/chaincode/shim" "github.com/hyperledger/fabric/core/chaincode/shim"
...@@ -36,6 +37,7 @@ import ( ...@@ -36,6 +37,7 @@ import (
"github.com/hyperledger/fabric/core/ledger/ledgermgmt" "github.com/hyperledger/fabric/core/ledger/ledgermgmt"
lutils "github.com/hyperledger/fabric/core/ledger/util" lutils "github.com/hyperledger/fabric/core/ledger/util"
"github.com/hyperledger/fabric/core/mocks/ccprovider" "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"
"github.com/hyperledger/fabric/msp/mgmt" "github.com/hyperledger/fabric/msp/mgmt"
"github.com/hyperledger/fabric/msp/mgmt/testtools" "github.com/hyperledger/fabric/msp/mgmt/testtools"
...@@ -61,9 +63,9 @@ func setupLedgerAndValidator(t *testing.T) (ledger.PeerLedger, Validator) { ...@@ -61,9 +63,9 @@ func setupLedgerAndValidator(t *testing.T) (ledger.PeerLedger, Validator) {
theLedger, err := ledgermgmt.CreateLedger(gb) theLedger, err := ledgermgmt.CreateLedger(gb)
assert.NoError(t, err) assert.NoError(t, err)
vcs := struct { vcs := struct {
*mockSupport *mocktxvalidator.Support
*semaphore.Weighted *semaphore.Weighted
}{&mockSupport{l: theLedger}, semaphore.NewWeighted(10)} }{&mocktxvalidator.Support{LedgerVal: theLedger, ACVal: &mockconfig.MockApplicationCapabilities{}}, semaphore.NewWeighted(10)}
theValidator := NewTxValidator(vcs) theValidator := NewTxValidator(vcs)
return theLedger, theValidator return theLedger, theValidator
...@@ -142,26 +144,6 @@ func putCCInfo(theLedger ledger.PeerLedger, ccname string, policy []byte, t *tes ...@@ -142,26 +144,6 @@ func putCCInfo(theLedger ledger.PeerLedger, ccname string, policy []byte, t *tes
putCCInfoWithVSCCAndVer(theLedger, ccname, "vscc", ccVersion, policy, t) 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) { func assertInvalid(block *common.Block, t *testing.T, code peer.TxValidationCode) {
txsFilter := lutils.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) txsFilter := lutils.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
assert.True(t, txsFilter.IsInvalid(0)) assert.True(t, txsFilter.IsInvalid(0))
...@@ -568,9 +550,9 @@ func (exec *mockQueryExecutor) Done() { ...@@ -568,9 +550,9 @@ func (exec *mockQueryExecutor) Done() {
func TestLedgerIsNoAvailable(t *testing.T) { func TestLedgerIsNoAvailable(t *testing.T) {
theLedger := new(mockLedger) theLedger := new(mockLedger)
vcs := struct { vcs := struct {
*mockSupport *mocktxvalidator.Support
*semaphore.Weighted *semaphore.Weighted
}{&mockSupport{l: theLedger}, semaphore.NewWeighted(10)} }{&mocktxvalidator.Support{LedgerVal: theLedger, ACVal: &mockconfig.MockApplicationCapabilities{}}, semaphore.NewWeighted(10)}
validator := NewTxValidator(vcs) validator := NewTxValidator(vcs)
ccID := "mycc" ccID := "mycc"
...@@ -596,9 +578,9 @@ func TestLedgerIsNoAvailable(t *testing.T) { ...@@ -596,9 +578,9 @@ func TestLedgerIsNoAvailable(t *testing.T) {
func TestValidationInvalidEndorsing(t *testing.T) { func TestValidationInvalidEndorsing(t *testing.T) {
theLedger := new(mockLedger) theLedger := new(mockLedger)
vcs := struct { vcs := struct {
*mockSupport *mocktxvalidator.Support
*semaphore.Weighted *semaphore.Weighted
}{&mockSupport{l: theLedger}, semaphore.NewWeighted(10)} }{&mocktxvalidator.Support{LedgerVal: theLedger, ACVal: &mockconfig.MockApplicationCapabilities{}}, semaphore.NewWeighted(10)}
validator := NewTxValidator(vcs) validator := NewTxValidator(vcs)
ccID := "mycc" ccID := "mycc"
......
...@@ -17,6 +17,7 @@ limitations under the License. ...@@ -17,6 +17,7 @@ limitations under the License.
package support package support
import ( import (
"github.com/hyperledger/fabric/common/channelconfig"
mockpolicies "github.com/hyperledger/fabric/common/mocks/policies" mockpolicies "github.com/hyperledger/fabric/common/mocks/policies"
"github.com/hyperledger/fabric/common/policies" "github.com/hyperledger/fabric/common/policies"
"github.com/hyperledger/fabric/core/ledger" "github.com/hyperledger/fabric/core/ledger"
...@@ -28,6 +29,11 @@ type Support struct { ...@@ -28,6 +29,11 @@ type Support struct {
LedgerVal ledger.PeerLedger LedgerVal ledger.PeerLedger
MSPManagerVal msp.MSPManager MSPManagerVal msp.MSPManager
ApplyVal error ApplyVal error
ACVal channelconfig.ApplicationCapabilities
}
func (ms *Support) Capabilities() channelconfig.ApplicationCapabilities {
return ms.ACVal
} }
// Ledger returns LedgerVal // Ledger returns LedgerVal
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment