Skip to content

Commit

Permalink
[FAB-3330] validate chaincode version
Browse files Browse the repository at this point in the history
1. Add VsccOutputData struct to keep output of vscc.
Vscc will return proposalResponsePayload(has verison info)
bytes contained in ChaincodeAction.
2. When committer validates transaction, check that the
chaincode version in ProposalResponse matches the
verision in lscc.
3. Add new ValidateCode to distinguash two kinds of invalid
reason because of chaincode upgrade.
4. vsccValidatorImpl will return latest chaincodeInstance
from lscc and vsccOutputData from vscc. So we can mock
system chaincode in UT.
5. Move ChaincodeInstance to sysccprovider to avoid
cycle import.

Change-Id: I45387f119054d64b57d28173cabda0194a9e3464
Signed-off-by: jiangyaoguo <jiangyaoguo@gmail.com>
  • Loading branch information
jiangyaoguo authored and Srinivasan Muralidharan committed Apr 27, 2017
1 parent ca3a1a2 commit f30fc74
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 135 deletions.
9 changes: 9 additions & 0 deletions common/ledger/testutil/test_helper.go
Expand Up @@ -125,6 +125,15 @@ func ConstructTestBlocks(t *testing.T, numBlocks int) []*common.Block {
return append(blocks, bg.NextTestBlocks(numBlocks-1)...)
}

// ConstructBytesProposalResponsePayload constructs a ProposalResponse byte with given chaincode version and simulationResults for testing
func ConstructBytesProposalResponsePayload(version string, simulationResults []byte) ([]byte, error) {
ccid := &pb.ChaincodeID{
Name: "foo",
Version: version,
}
return ptestutils.ConstractBytesProposalResponsePayload(util.GetTestChainID(), ccid, nil, simulationResults)
}

func newBlock(env []*common.Envelope, blockNum uint64, previousHash []byte) *common.Block {
block := common.NewBlock(blockNum, previousHash)
for i := 0; i < len(env); i++ {
Expand Down
93 changes: 66 additions & 27 deletions core/committer/txvalidator/txvalidator_test.go
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/hyperledger/fabric/common/configtx/test"
"github.com/hyperledger/fabric/common/ledger/testutil"
util2 "github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/common/sysccprovider"
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
"github.com/hyperledger/fabric/core/ledger/util"
ledgerUtil "github.com/hyperledger/fabric/core/ledger/util"
Expand All @@ -38,7 +39,7 @@ import (
"github.com/stretchr/testify/assert"
)

func TestFirstBlockValidation(t *testing.T) {
func TestBlockValidation(t *testing.T) {
viper.Set("peer.fileSystemPath", "/tmp/fabric/txvalidatortest")
ledgermgmt.InitializeTestEnv()
defer ledgermgmt.CleanupTestEnv()
Expand All @@ -48,11 +49,11 @@ func TestFirstBlockValidation(t *testing.T) {
ledger, _ := ledgermgmt.CreateLedger(gb)
defer ledger.Close()

tValidator := &txValidator{&mocktxvalidator.Support{LedgerVal: ledger}, &validator.MockVsccValidator{}}

bcInfo, _ := ledger.GetBlockchainInfo()
testutil.AssertEquals(t, bcInfo, &common.BlockchainInfo{
Height: 1, CurrentBlockHash: gbHash, PreviousBlockHash: nil})
chaincodeIns := &sysccprovider.ChaincodeInstance{
ChaincodeName: "foo",
ChaincodeVersion: "v1",
ChainID: util2.GetTestChainID(),
}

simulator, _ := ledger.NewTxSimulator()
simulator.SetState("ns1", "key1", []byte("value1"))
Expand All @@ -61,12 +62,50 @@ func TestFirstBlockValidation(t *testing.T) {
simulator.Done()

simRes, _ := simulator.GetTxSimulationResults()

prespPaylBytes, err := testutil.ConstructBytesProposalResponsePayload("v1", simRes)
if err != nil {
t.Fatalf("Could not construct ProposalResponsePayload bytes, err: %s", err)
}

mockVsccValidator := &validator.MockVsccValidator{
CIns: chaincodeIns,
RespPayl: prespPaylBytes,
}
tValidator := &txValidator{&mocktxvalidator.Support{LedgerVal: ledger}, mockVsccValidator}

bcInfo, _ := ledger.GetBlockchainInfo()
testutil.AssertEquals(t, bcInfo, &common.BlockchainInfo{
Height: 1, CurrentBlockHash: gbHash, PreviousBlockHash: nil})

block := testutil.ConstructBlock(t, 1, gbHash, [][]byte{simRes}, true)

tValidator.Validate(block)

txsfltr := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
assert.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_VALID))

// upgrade chaincode version
upgradeChaincodeIns := &sysccprovider.ChaincodeInstance{
ChaincodeName: "foo",
ChaincodeVersion: "v2", // new version
ChainID: util2.GetTestChainID(),
}

newMockVsccValidator := &validator.MockVsccValidator{
CIns: upgradeChaincodeIns,
RespPayl: prespPaylBytes,
}
newTxValidator := &txValidator{&mocktxvalidator.Support{LedgerVal: ledger}, newMockVsccValidator}

// generate new block
newBlock := testutil.ConstructBlock(t, 2, block.Header.Hash(), [][]byte{simRes}, true) // contains one tx with chaincode version v1

newTxValidator.Validate(newBlock)

// tx should be invalided because of chaincode upgrade
txsfltr = util.TxValidationFlags(newBlock.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
assert.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_EXPIRED_CHAINCODE))
}

func TestNewTxValidator_DuplicateTransactions(t *testing.T) {
Expand Down Expand Up @@ -186,12 +225,12 @@ func TestGetTxCCInstance(t *testing.T) {
payload, err := utils.GetPayload(env)
assert.NoError(t, err)

expectInvokeCCIns := &ChaincodeInstance{
expectInvokeCCIns := &sysccprovider.ChaincodeInstance{
ChainID: chainID,
ChaincodeName: "lscc",
ChaincodeVersion: "",
}
expectUpgradeCCIns := &ChaincodeInstance{
expectUpgradeCCIns := &sysccprovider.ChaincodeInstance{
ChainID: chainID,
ChaincodeName: upgradeCCName,
ChaincodeVersion: upgradeCCVersion,
Expand All @@ -207,20 +246,20 @@ func TestGetTxCCInstance(t *testing.T) {
}

func TestInvalidTXsForUpgradeCC(t *testing.T) {
txsChaincodeNames := map[int]*ChaincodeInstance{
0: &ChaincodeInstance{"chain0", "cc0", "v0"}, // invoke cc0/chain0:v0, should not be affected by upgrade tx in other chain
1: &ChaincodeInstance{"chain1", "cc0", "v0"}, // invoke cc0/chain1:v0, should be invalided by cc1/chain1 upgrade tx
2: &ChaincodeInstance{"chain1", "lscc", ""}, // upgrade cc0/chain1 to v1, should be invalided by latter cc0/chain1 upgtade tx
3: &ChaincodeInstance{"chain1", "cc0", "v0"}, // invoke cc0/chain1:v0, should be invalided by cc1/chain1 upgrade tx
4: &ChaincodeInstance{"chain1", "cc0", "v1"}, // invoke cc0/chain1:v1, should be invalided by cc1/chain1 upgrade tx
5: &ChaincodeInstance{"chain1", "cc1", "v0"}, // invoke cc1/chain1:v0, should not be affected by other chaincode upgrade tx
6: &ChaincodeInstance{"chain1", "lscc", ""}, // upgrade cc0/chain1 to v2, should be invalided by latter cc0/chain1 upgtade tx
7: &ChaincodeInstance{"chain1", "lscc", ""}, // upgrade cc0/chain1 to v3
}
upgradedChaincodes := map[int]*ChaincodeInstance{
2: &ChaincodeInstance{"chain1", "cc0", "v1"},
6: &ChaincodeInstance{"chain1", "cc0", "v2"},
7: &ChaincodeInstance{"chain1", "cc0", "v3"},
txsChaincodeNames := map[int]*sysccprovider.ChaincodeInstance{
0: &sysccprovider.ChaincodeInstance{"chain0", "cc0", "v0"}, // invoke cc0/chain0:v0, should not be affected by upgrade tx in other chain
1: &sysccprovider.ChaincodeInstance{"chain1", "cc0", "v0"}, // invoke cc0/chain1:v0, should be invalided by cc1/chain1 upgrade tx
2: &sysccprovider.ChaincodeInstance{"chain1", "lscc", ""}, // upgrade cc0/chain1 to v1, should be invalided by latter cc0/chain1 upgtade tx
3: &sysccprovider.ChaincodeInstance{"chain1", "cc0", "v0"}, // invoke cc0/chain1:v0, should be invalided by cc1/chain1 upgrade tx
4: &sysccprovider.ChaincodeInstance{"chain1", "cc0", "v1"}, // invoke cc0/chain1:v1, should be invalided by cc1/chain1 upgrade tx
5: &sysccprovider.ChaincodeInstance{"chain1", "cc1", "v0"}, // invoke cc1/chain1:v0, should not be affected by other chaincode upgrade tx
6: &sysccprovider.ChaincodeInstance{"chain1", "lscc", ""}, // upgrade cc0/chain1 to v2, should be invalided by latter cc0/chain1 upgtade tx
7: &sysccprovider.ChaincodeInstance{"chain1", "lscc", ""}, // upgrade cc0/chain1 to v3
}
upgradedChaincodes := map[int]*sysccprovider.ChaincodeInstance{
2: &sysccprovider.ChaincodeInstance{"chain1", "cc0", "v1"},
6: &sysccprovider.ChaincodeInstance{"chain1", "cc0", "v2"},
7: &sysccprovider.ChaincodeInstance{"chain1", "cc0", "v3"},
}

txsfltr := ledgerUtil.NewTxValidationFlags(8)
Expand All @@ -235,12 +274,12 @@ func TestInvalidTXsForUpgradeCC(t *testing.T) {

expectTxsFltr := ledgerUtil.NewTxValidationFlags(8)
expectTxsFltr.SetFlag(0, peer.TxValidationCode_VALID)
expectTxsFltr.SetFlag(1, peer.TxValidationCode_EXPIRED_CHAINCODE)
expectTxsFltr.SetFlag(2, peer.TxValidationCode_EXPIRED_CHAINCODE)
expectTxsFltr.SetFlag(3, peer.TxValidationCode_EXPIRED_CHAINCODE)
expectTxsFltr.SetFlag(4, peer.TxValidationCode_EXPIRED_CHAINCODE)
expectTxsFltr.SetFlag(1, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT)
expectTxsFltr.SetFlag(2, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT)
expectTxsFltr.SetFlag(3, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT)
expectTxsFltr.SetFlag(4, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT)
expectTxsFltr.SetFlag(5, peer.TxValidationCode_VALID)
expectTxsFltr.SetFlag(6, peer.TxValidationCode_EXPIRED_CHAINCODE)
expectTxsFltr.SetFlag(6, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT)
expectTxsFltr.SetFlag(7, peer.TxValidationCode_VALID)

tValidator := &txValidator{}
Expand Down

0 comments on commit f30fc74

Please sign in to comment.