Skip to content

Commit

Permalink
[FAB-1812] Pass configtx.Manager.Apply to validate
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-1812

The peer needs to apply configuration transactions as they are
committed.  This changeset hooks the configtx.Manager.Apply method into
core/committer/txvalidator/validator.go so that configuration is updated
as configuration blocks are committed.

Because it was in the same path, it also passes the MSPManager to the
validator to remove one of the dependencies on the throwaway MSP
multichain manager.

Change-Id: I4d606d850dddb684468d7a5dd7257e8dd967ad28
Signed-off-by: Jason Yellick <[email protected]>
  • Loading branch information
Jason Yellick committed Jan 24, 2017
1 parent 2be1717 commit 9dbaeca
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 32 deletions.
5 changes: 4 additions & 1 deletion core/committer/committer_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,13 @@ func NewLedgerCommitter(ledger ledger.PeerLedger, validator txvalidator.Validato
}

// Commit commits block to into the ledger
// Note, it is important that this always be called serially
func (lc *LedgerCommitter) Commit(block *common.Block) error {
// Validate and mark invalid transactions
logger.Debug("Validating block")
lc.validator.Validate(block)
if err := lc.validator.Validate(block); err != nil {
return err
}

if err := lc.ledger.Commit(block); err != nil {
return err
Expand Down
5 changes: 3 additions & 2 deletions core/committer/txvalidator/txvalidator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
"github.com/hyperledger/fabric/core/ledger/testutil"
"github.com/hyperledger/fabric/core/ledger/util"
mocktxvalidator "github.com/hyperledger/fabric/core/mocks/txvalidator"
"github.com/hyperledger/fabric/core/mocks/validator"
"github.com/hyperledger/fabric/protos/common"
pb "github.com/hyperledger/fabric/protos/peer"
Expand All @@ -39,7 +40,7 @@ func TestKVLedgerBlockStorage(t *testing.T) {
ledger, _ := ledgermgmt.CreateLedger("TestLedger")
defer ledger.Close()

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

bcInfo, _ := ledger.GetBlockchainInfo()
testutil.AssertEquals(t, bcInfo, &pb.BlockchainInfo{
Expand Down Expand Up @@ -70,7 +71,7 @@ func TestNewTxValidator_DuplicateTransactions(t *testing.T) {
ledger, _ := ledgermgmt.CreateLedger("TestLedger")
defer ledger.Close()

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

// Create simeple endorsement transaction
payload := &common.Payload{
Expand Down
60 changes: 39 additions & 21 deletions core/committer/txvalidator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,30 @@ import (
"github.com/hyperledger/fabric/core/common/validation"
"github.com/hyperledger/fabric/core/ledger"
ledgerUtil "github.com/hyperledger/fabric/core/ledger/util"
"github.com/hyperledger/fabric/core/peer/msp"
"github.com/hyperledger/fabric/msp"
"github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/utils"
"github.com/op/go-logging"
"github.com/syndtr/goleveldb/leveldb/errors"
)

// Support provides all of the needed to evaluate the VSCC
type Support interface {
// Ledger returns the ledger associated with this validator
Ledger() ledger.PeerLedger

// MSPManager returns the MSP manager for this chain
MSPManager() msp.MSPManager

// Apply attempts to apply a configtx to become the new configuration
Apply(configtx *common.ConfigurationEnvelope) error
}

//Validator interface which defines API to validate block transactions
// and return the bit array mask indicating invalid transactions which
// didn't pass validation.
type Validator interface {
Validate(block *common.Block)
Validate(block *common.Block) error
}

// private interface to decouple tx validator
Expand All @@ -51,16 +62,16 @@ type vsccValidator interface {
// vsccValidator implementation which used to call
// vscc chaincode and validate block transactions
type vsccValidatorImpl struct {
ledger ledger.PeerLedger
support Support
ccprovider ccprovider.ChaincodeProvider
}

// implementation of Validator interface, keeps
// reference to the ledger to enable tx simulation
// and execution of vscc
type txValidator struct {
ledger ledger.PeerLedger
vscc vsccValidator
support Support
vscc vsccValidator
}

var logger *logging.Logger // package-level logger
Expand All @@ -71,17 +82,17 @@ func init() {
}

// NewTxValidator creates new transactions validator
func NewTxValidator(ledger ledger.PeerLedger) Validator {
func NewTxValidator(support Support) Validator {
// Encapsulates interface implementation
return &txValidator{ledger, &vsccValidatorImpl{ledger: ledger, ccprovider: ccprovider.GetChaincodeProvider()}}
return &txValidator{support, &vsccValidatorImpl{support: support, ccprovider: ccprovider.GetChaincodeProvider()}}
}

func (v *txValidator) chainExists(chain string) bool {
// TODO: implement this function!
return true
}

func (v *txValidator) Validate(block *common.Block) {
func (v *txValidator) Validate(block *common.Block) error {
logger.Debug("START Block Validation")
defer logger.Debug("END Block Validation")
txsfltr := ledgerUtil.NewFilterBitArray(uint(len(block.Data.Data)))
Expand Down Expand Up @@ -117,7 +128,7 @@ func (v *txValidator) Validate(block *common.Block) {
if common.HeaderType(payload.Header.ChainHeader.Type) == common.HeaderType_ENDORSER_TRANSACTION {
// Check duplicate transactions
txID := payload.Header.ChainHeader.TxID
if _, err := v.ledger.GetTransactionByID(txID); err == nil {
if _, err := v.support.Ledger().GetTransactionByID(txID); err == nil {
logger.Warning("Duplicate transaction found, ", txID, ", skipping")
continue
}
Expand All @@ -130,13 +141,19 @@ func (v *txValidator) Validate(block *common.Block) {
continue
}
} else if common.HeaderType(payload.Header.ChainHeader.Type) == common.HeaderType_CONFIGURATION_TRANSACTION {
// TODO: here we should call CSCC and pass it the config tx
// note that there is quite a bit more validation necessary
// on this tx, namely, validation that each config item has
// signature matching the policy required for the item from
// the existing configuration; this is taken care of nicely
// by configtx.Manager (see fabric/common/configtx).
logger.Debug("config transaction received for chain %s", chain)
configEnvelope, err := utils.UnmarshalConfigurationEnvelope(payload.Data)
if err != nil {
err := fmt.Errorf("Error unmarshaling configuration which passed initial validity checks: %s", err)
logger.Critical(err)
return err
}

if err := v.support.Apply(configEnvelope); err != nil {
err := fmt.Errorf("Error validating configuration which passed initial validity checks: %s", err)
logger.Critical(err)
return err
}
logger.Debugf("config transaction received for chain %s", chain)
}

if _, err := proto.Marshal(env); err != nil {
Expand All @@ -155,16 +172,17 @@ func (v *txValidator) Validate(block *common.Block) {
utils.InitBlockMetadata(block)
// Serialize invalid transaction bit array into block metadata field
block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsfltr.ToBytes()

return nil
}

// getHardcodedPolicy returns a policy that requests
// getSemiHardcodedPolicy returns a policy that requests
// one valid signature from the first MSP in this
// chain's MSP manager
// FIXME: this needs to be removed as soon as we extract the policy from LCCC
func getHardcodedPolicy(chainID string) ([]byte, error) {
func getSemiHardcodedPolicy(chainID string, mspMgr msp.MSPManager) ([]byte, error) {
// 1) determine the MSP identifier for the first MSP in this chain
var msp msp.MSP
mspMgr := mspmgmt.GetManagerForChain(chainID)
msps, err := mspMgr.GetMSPs()
if err != nil {
return nil, fmt.Errorf("Could not retrieve the MSPs for the chain manager, err %s", err)
Expand Down Expand Up @@ -215,7 +233,7 @@ func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []b
// by the deployer and can be retrieved via LCCC: we create
// a policy that requests 1 valid signature from this chain's
// MSP
policy, err := getHardcodedPolicy(chainID)
policy, err := getSemiHardcodedPolicy(chainID, v.support.MSPManager())
if err != nil {
return err
}
Expand All @@ -226,7 +244,7 @@ func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []b
// args[2] - serialized policy
args := [][]byte{[]byte(""), envBytes, policy}

ctxt, err := v.ccprovider.GetContext(v.ledger)
ctxt, err := v.ccprovider.GetContext(v.support.Ledger())
if err != nil {
logger.Errorf("Cannot obtain context for txid=%s, err %s", txid, err)
return err
Expand Down
44 changes: 44 additions & 0 deletions core/mocks/txvalidator/support.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
Copyright IBM Corp. 2017 All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package support

import (
"github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/msp"
"github.com/hyperledger/fabric/protos/common"
)

type Support struct {
LedgerVal ledger.PeerLedger
MSPManagerVal msp.MSPManager
ApplyVal error
}

// Ledger returns LedgerVal
func (ms *Support) Ledger() ledger.PeerLedger {
return ms.LedgerVal
}

// MSPManager returns MSPManagerVal
func (ms *Support) MSPManager() msp.MSPManager {
return ms.MSPManagerVal
}

// Apply returns ApplyVal
func (ms *Support) Apply(configtx *common.ConfigurationEnvelope) error {
return ms.ApplyVal
}
5 changes: 3 additions & 2 deletions core/mocks/validator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ import "github.com/hyperledger/fabric/protos/common"
type MockValidator struct {
}

// Validate does nothing
func (m *MockValidator) Validate(block *common.Block) {
// Validate does nothing, returning no error
func (m *MockValidator) Validate(block *common.Block) error {
return nil
}

// MockVsccValidator is a mock implementation of the VSCC validation interface
Expand Down
54 changes: 48 additions & 6 deletions core/peer/peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/op/go-logging"
"github.com/spf13/viper"

"github.com/hyperledger/fabric/common/configtx"
"github.com/hyperledger/fabric/core/comm"
"github.com/hyperledger/fabric/core/committer"
"github.com/hyperledger/fabric/core/committer/txvalidator"
Expand All @@ -41,12 +42,25 @@ import (

var peerLogger = logging.MustGetLogger("peer")

type chainSupport struct {
configtx.Manager
ledger ledger.PeerLedger
mspmgr msp.MSPManager
}

func (cs *chainSupport) Ledger() ledger.PeerLedger {
return cs.ledger
}

func (cs *chainSupport) MSPManager() msp.MSPManager {
return cs.mspmgr
}

// chain is a local struct to manage objects in a chain
type chain struct {
cs *chainSupport
cb *common.Block
ledger ledger.PeerLedger
committer committer.Committer
mspmgr msp.MSPManager
}

// chains is a local map of chainID->chainObject
Expand Down Expand Up @@ -146,13 +160,33 @@ func getCurrConfigBlockFromLedger(ledger ledger.PeerLedger) (*common.Block, erro

// createChain creates a new chain object and insert it into the chains
func createChain(cid string, ledger ledger.PeerLedger, cb *common.Block) error {
c := committer.NewLedgerCommitter(ledger, txvalidator.NewTxValidator(ledger))

configEnvelope, _, err := utils.BreakOutBlockToConfigurationEnvelope(cb)
if err != nil {
return err
}

configtxInitializer := configtx.NewInitializer()
// TODO Hook peer shared config manager in here once it exists
configtxManager, err := configtx.NewManagerImpl(configEnvelope, configtxInitializer)
if err != nil {
return err
}

// TODO Move to the configtx.Handler interface (which MSP already implements)
mgr, err := mspmgmt.GetMSPManagerFromBlock(cid, cb)
if err != nil {
return err
}

cs := &chainSupport{
Manager: configtxManager,
ledger: ledger,
mspmgr: mgr,
}

c := committer.NewLedgerCommitter(ledger, txvalidator.NewTxValidator(cs))

// TODO This should be called from a configtx.Manager but it's not
// implemented yet. When it will be, this needs to move there,
// and the inner fields (AnchorPeers) only should be passed to this.
Expand All @@ -162,7 +196,15 @@ func createChain(cid string, ledger ledger.PeerLedger, cb *common.Block) error {

chains.Lock()
defer chains.Unlock()
chains.list[cid] = &chain{cb: cb, ledger: ledger, mspmgr: mgr, committer: c}
chains.list[cid] = &chain{
cs: &chainSupport{
Manager: configtxManager,
ledger: ledger,
mspmgr: mgr,
},
cb: cb,
committer: c,
}
return nil
}

Expand Down Expand Up @@ -191,7 +233,7 @@ func MockCreateChain(cid string) error {

chains.Lock()
defer chains.Unlock()
chains.list[cid] = &chain{ledger: ledger}
chains.list[cid] = &chain{cs: &chainSupport{ledger: ledger}}

return nil
}
Expand All @@ -202,7 +244,7 @@ func GetLedger(cid string) ledger.PeerLedger {
chains.RLock()
defer chains.RUnlock()
if c, ok := chains.list[cid]; ok {
return c.ledger
return c.cs.ledger
}
return nil
}
Expand Down

0 comments on commit 9dbaeca

Please sign in to comment.