Skip to content

Commit

Permalink
[FAB-6229] validator accepts RESOURCE_UPDATE txes
Browse files Browse the repository at this point in the history
This change set introudces support (and tests) to handle incoming txes with
the new type HeaderType_PEER_RESOURCE_UPDATE.

Change-Id: I12e615a911d9210cf5dbb696d4f9ff03d166d60c
Signed-off-by: Alessandro Sorniotti <ale.linux@sopit.net>
  • Loading branch information
ale-linux committed Dec 8, 2017
1 parent ff0b4fa commit f47dd7f
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 23 deletions.
25 changes: 16 additions & 9 deletions core/committer/txvalidator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,26 @@ package txvalidator
import (
"fmt"

"golang.org/x/net/context"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/cauthdsl"
"github.com/hyperledger/fabric/common/channelconfig"
"github.com/hyperledger/fabric/common/configtx"
"github.com/hyperledger/fabric/common/flogging"
"github.com/hyperledger/fabric/common/resourcesconfig"
coreUtil "github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/core/common/ccprovider"
"github.com/hyperledger/fabric/core/common/sysccprovider"
"github.com/hyperledger/fabric/core/common/validation"
"github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
ledgerUtil "github.com/hyperledger/fabric/core/ledger/util"
"github.com/hyperledger/fabric/msp"

"github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/peer"
"github.com/hyperledger/fabric/protos/utils"
"github.com/op/go-logging"

"github.com/hyperledger/fabric/common/cauthdsl"
"github.com/hyperledger/fabric/common/channelconfig"
"github.com/hyperledger/fabric/common/resourcesconfig"
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
"golang.org/x/net/context"
)

// Support provides all of the needed to evaluate the VSCC
Expand Down Expand Up @@ -337,7 +334,7 @@ func validateTx(req *blockValidationRequest, results chan<- *blockValidationResu
var txsChaincodeName *sysccprovider.ChaincodeInstance
var txsUpgradedChaincode *sysccprovider.ChaincodeInstance

if payload, txResult = validation.ValidateTransaction(env); txResult != peer.TxValidationCode_VALID {
if payload, txResult = validation.ValidateTransaction(env, v.support.Capabilities()); txResult != peer.TxValidationCode_VALID {
logger.Errorf("Invalid transaction with index %d", tIdx)
results <- &blockValidationResult{
tIdx: tIdx,
Expand Down Expand Up @@ -443,6 +440,16 @@ func validateTx(req *blockValidationRequest, results chan<- *blockValidationResu
return
}
logger.Debugf("config transaction received for chain %s", channel)
} else if common.HeaderType(chdr.Type) == common.HeaderType_PEER_RESOURCE_UPDATE {
// FIXME: in the context of FAB-7341, we should introduce validation
// for this kind of transaction here. For now we just ignore this
// type of transaction and delegate its validation to other components

results <- &blockValidationResult{
tIdx: tIdx,
err: nil,
}
return
} else {
logger.Warningf("Unknown transaction type [%s] in block number [%d] transaction index [%d]",
common.HeaderType(chdr.Type), block.Header.Number, tIdx)
Expand Down
58 changes: 54 additions & 4 deletions core/committer/txvalidator/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,22 +82,22 @@ func createRWset(t *testing.T, ccnames ...string) []byte {
return rwsetBytes
}

func getProposal(ccID string) (*peer.Proposal, error) {
func getProposalWithType(ccID string, pType common.HeaderType) (*peer.Proposal, error) {
cis := &peer.ChaincodeInvocationSpec{
ChaincodeSpec: &peer.ChaincodeSpec{
ChaincodeId: &peer.ChaincodeID{Name: ccID, Version: ccVersion},
Input: &peer.ChaincodeInput{Args: [][]byte{[]byte("func")}},
Type: peer.ChaincodeSpec_GOLANG}}

proposal, _, err := utils.CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), cis, signerSerialized)
proposal, _, err := utils.CreateProposalFromCIS(pType, util.GetTestChainID(), cis, signerSerialized)
return proposal, err
}

const ccVersion = "1.0"

func getEnv(ccID string, res []byte, t *testing.T) *common.Envelope {
func getEnvWithType(ccID string, res []byte, pType common.HeaderType, t *testing.T) *common.Envelope {
// get a toy proposal
prop, err := getProposal(ccID)
prop, err := getProposalWithType(ccID, pType)
assert.NoError(t, err)

response := &peer.Response{Status: 200}
Expand All @@ -113,6 +113,10 @@ func getEnv(ccID string, res []byte, t *testing.T) *common.Envelope {
return tx
}

func getEnv(ccID string, res []byte, t *testing.T) *common.Envelope {
return getEnvWithType(ccID, res, common.HeaderType_ENDORSER_TRANSACTION, t)
}

func putCCInfoWithVSCCAndVer(theLedger ledger.PeerLedger, ccname, vscc, ver string, policy []byte, t *testing.T) {
cd := &ccp.ChaincodeData{
Name: ccname,
Expand Down Expand Up @@ -615,6 +619,52 @@ func TestValidationInvalidEndorsing(t *testing.T) {
assertInvalid(b, t, peer.TxValidationCode_ENDORSEMENT_POLICY_FAILURE)
}

func TestValidationResourceUpdate(t *testing.T) {
theLedger := new(mockLedger)
sup := &mocktxvalidator.Support{LedgerVal: theLedger, ACVal: &mockconfig.MockApplicationCapabilities{}}
vcs := struct {
*mocktxvalidator.Support
*semaphore.Weighted
}{sup, semaphore.NewWeighted(10)}
validator := NewTxValidator(vcs)

ccID := "mycc"
tx := getEnvWithType(ccID, createRWset(t, ccID), common.HeaderType_PEER_RESOURCE_UPDATE, t)

theLedger.On("GetTransactionByID", mock.Anything).Return(&peer.ProcessedTransaction{}, errors.New("Cannot find the transaction"))

cd := &ccp.ChaincodeData{
Name: ccID,
Version: ccVersion,
Vscc: "vscc",
Policy: signedByAnyMember([]string{"DEFAULT"}),
}

cdbytes := utils.MarshalOrPanic(cd)

queryExecutor := new(mockQueryExecutor)
queryExecutor.On("GetState", "lscc", ccID).Return(cdbytes, nil)
theLedger.On("NewQueryExecutor", mock.Anything).Return(queryExecutor, nil)

b1 := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}
b2 := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}}

// Keep default callback
c := executeChaincodeProvider.getCallback()
executeChaincodeProvider.setCallback(func() (*peer.Response, *peer.ChaincodeEvent, error) {
return &peer.Response{Status: shim.ERROR}, nil, nil
})
err := validator.Validate(b1)
assert.NoError(t, err)
sup.ACVal = &mockconfig.MockApplicationCapabilities{LifecycleViaConfigRv: true}
err = validator.Validate(b2)
assert.NoError(t, err)
// Restore default callback
executeChaincodeProvider.setCallback(c)
assertInvalid(b1, t, peer.TxValidationCode_UNSUPPORTED_TX_PAYLOAD)
assertValid(b2, t)
}

type ccResultCallback func() (*peer.Response, *peer.ChaincodeEvent, error)

type ccExecuteChaincode struct {
Expand Down
3 changes: 2 additions & 1 deletion core/common/validation/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package validation
import (
"testing"

"github.com/hyperledger/fabric/common/mocks/config"
"github.com/hyperledger/fabric/common/tools/configtxgen/encoder"
genesisconfig "github.com/hyperledger/fabric/common/tools/configtxgen/localconfig"
"github.com/hyperledger/fabric/common/util"
Expand Down Expand Up @@ -52,7 +53,7 @@ func TestValidateConfigTx(t *testing.T) {
}),
}
updateResult.Signature, _ = signer.Sign(updateResult.Payload)
_, txResult := ValidateTransaction(updateResult)
_, txResult := ValidateTransaction(updateResult, &config.MockApplicationCapabilities{})
if txResult != peer.TxValidationCode_VALID {
t.Fatalf("ValidateTransaction failed, err %s", err)
return
Expand Down
13 changes: 7 additions & 6 deletions core/common/validation/fullflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"testing"
"time"

"github.com/hyperledger/fabric/common/mocks/config"
mmsp "github.com/hyperledger/fabric/common/mocks/msp"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/msp"
Expand Down Expand Up @@ -157,7 +158,7 @@ func TestGoodPath(t *testing.T) {
}

// validate the transaction
payl, txResult := ValidateTransaction(tx)
payl, txResult := ValidateTransaction(tx, &config.MockApplicationCapabilities{})
if txResult != peer.TxValidationCode_VALID {
t.Fatalf("ValidateTransaction failed, err %s", err)
return
Expand Down Expand Up @@ -217,7 +218,7 @@ func TestTXWithTwoActionsRejected(t *testing.T) {
}

// validate the transaction
_, txResult := ValidateTransaction(tx)
_, txResult := ValidateTransaction(tx, &config.MockApplicationCapabilities{})
if txResult == peer.TxValidationCode_VALID {
t.Fatalf("ValidateTransaction should have failed")
return
Expand Down Expand Up @@ -333,7 +334,7 @@ func TestBadTx(t *testing.T) {
copy(paylCopy, paylOrig)
paylCopy[i] = byte(int(paylCopy[i]+1) % 255)
// validate the transaction it should fail
_, txResult := ValidateTransaction(&common.Envelope{Signature: tx.Signature, Payload: paylCopy})
_, txResult := ValidateTransaction(&common.Envelope{Signature: tx.Signature, Payload: paylCopy}, &config.MockApplicationCapabilities{})
if txResult == peer.TxValidationCode_VALID {
t.Fatal("ValidateTransaction should have failed")
return
Expand All @@ -351,7 +352,7 @@ func TestBadTx(t *testing.T) {
corrupt(tx.Signature)

// validate the transaction it should fail
_, txResult := ValidateTransaction(tx)
_, txResult := ValidateTransaction(tx, &config.MockApplicationCapabilities{})
if txResult == peer.TxValidationCode_VALID {
t.Fatal("ValidateTransaction should have failed")
return
Expand Down Expand Up @@ -394,7 +395,7 @@ func Test2EndorsersAgree(t *testing.T) {
}

// validate the transaction
_, txResult := ValidateTransaction(tx)
_, txResult := ValidateTransaction(tx, &config.MockApplicationCapabilities{})
if txResult != peer.TxValidationCode_VALID {
t.Fatalf("ValidateTransaction failed, err %s", err)
return
Expand Down Expand Up @@ -438,7 +439,7 @@ func Test2EndorsersDisagree(t *testing.T) {
}

func TestInvocationsBadArgs(t *testing.T) {
_, code := ValidateTransaction(nil)
_, code := ValidateTransaction(nil, &config.MockApplicationCapabilities{})
assert.Equal(t, code, peer.TxValidationCode_NIL_ENVELOPE)
err := validateEndorserTransaction(nil, nil)
assert.Error(t, err)
Expand Down
16 changes: 14 additions & 2 deletions core/common/validation/msgvalidation.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"errors"
"fmt"

"github.com/hyperledger/fabric/common/channelconfig"
"github.com/hyperledger/fabric/common/flogging"
mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
"github.com/hyperledger/fabric/protos/common"
Expand Down Expand Up @@ -115,6 +116,9 @@ func ValidateProposalMessage(signedProp *pb.SignedProposal) (*pb.Proposal, *comm

// continue the validation in a way that depends on the type specified in the header
switch common.HeaderType(chdr.Type) {
case common.HeaderType_PEER_RESOURCE_UPDATE:
// no additional validation required for transactions of this type
return prop, hdr, nil, err
case common.HeaderType_CONFIG:
//which the types are different the validation is the same
//viz, validate a proposal to a chaincode. If we need other
Expand Down Expand Up @@ -208,7 +212,8 @@ func validateChannelHeader(cHdr *common.ChannelHeader) error {
// validate the header type
if common.HeaderType(cHdr.Type) != common.HeaderType_ENDORSER_TRANSACTION &&
common.HeaderType(cHdr.Type) != common.HeaderType_CONFIG_UPDATE &&
common.HeaderType(cHdr.Type) != common.HeaderType_CONFIG {
common.HeaderType(cHdr.Type) != common.HeaderType_CONFIG &&
common.HeaderType(cHdr.Type) != common.HeaderType_PEER_RESOURCE_UPDATE {
return fmt.Errorf("invalid header type %s", common.HeaderType(cHdr.Type))
}

Expand Down Expand Up @@ -358,7 +363,7 @@ func validateEndorserTransaction(data []byte, hdr *common.Header) error {
}

// ValidateTransaction checks that the transaction envelope is properly formed
func ValidateTransaction(e *common.Envelope) (*common.Payload, pb.TxValidationCode) {
func ValidateTransaction(e *common.Envelope, c channelconfig.ApplicationCapabilities) (*common.Payload, pb.TxValidationCode) {
putilsLogger.Debugf("ValidateTransactionEnvelope starts for envelope %p", e)

// check for nil argument
Expand Down Expand Up @@ -417,6 +422,13 @@ func ValidateTransaction(e *common.Envelope) (*common.Payload, pb.TxValidationCo
} else {
return payload, pb.TxValidationCode_VALID
}
case common.HeaderType_PEER_RESOURCE_UPDATE:
if !c.LifecycleViaConfig() {
return nil, pb.TxValidationCode_UNSUPPORTED_TX_PAYLOAD
}

// perform similar validation to common.HeaderType_CONFIG
fallthrough
case common.HeaderType_CONFIG:
// Config transactions have signatures inside which will be validated, especially at genesis there may be no creator or
// signature on the outermost envelope
Expand Down
42 changes: 42 additions & 0 deletions core/common/validation/resourceupdate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
Copyright IBM Corp. 2016 All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package validation

import (
"testing"

"github.com/docker/docker/pkg/testutil/assert"
"github.com/hyperledger/fabric/common/mocks/config"
"github.com/hyperledger/fabric/common/util"
cb "github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/peer"
"github.com/hyperledger/fabric/protos/utils"
)

func TestValidateResourceUpdateTx(t *testing.T) {
chainID := util.GetTestChainID()

updateResult := &cb.Envelope{
Payload: utils.MarshalOrPanic(&cb.Payload{Header: &cb.Header{
ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{
Type: int32(cb.HeaderType_PEER_RESOURCE_UPDATE),
ChannelId: chainID,
}),
SignatureHeader: utils.MarshalOrPanic(&cb.SignatureHeader{
Creator: signerSerialized,
Nonce: utils.CreateNonceOrPanic(),
}),
},
Data: utils.MarshalOrPanic(&cb.ConfigEnvelope{LastUpdate: &cb.Envelope{}}),
}),
}
updateResult.Signature, _ = signer.Sign(updateResult.Payload)
_, txResult := ValidateTransaction(updateResult, &config.MockApplicationCapabilities{})
assert.Equal(t, txResult, peer.TxValidationCode_UNSUPPORTED_TX_PAYLOAD)
_, txResult = ValidateTransaction(updateResult, &config.MockApplicationCapabilities{LifecycleViaConfigRv: true})
assert.Equal(t, txResult, peer.TxValidationCode_VALID)
}
3 changes: 2 additions & 1 deletion core/scc/escc/endorser_onevalidsignature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"testing"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/mocks/config"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/core/common/validation"
Expand Down Expand Up @@ -370,7 +371,7 @@ func validateProposalResponse(prBytes []byte, proposal *pb.Proposal, ccid *pb.Ch
}

// validate the transaction
_, txResult := validation.ValidateTransaction(tx)
_, txResult := validation.ValidateTransaction(tx, &config.MockApplicationCapabilities{})
if txResult != pb.TxValidationCode_VALID {
return err
}
Expand Down

0 comments on commit f47dd7f

Please sign in to comment.