github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/orderer/multichain/chainsupport.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8                   http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package multichain
    18  
    19  import (
    20  	"github.com/hyperledger/fabric/common/config"
    21  	"github.com/hyperledger/fabric/common/crypto"
    22  	"github.com/hyperledger/fabric/common/policies"
    23  	"github.com/hyperledger/fabric/common/util"
    24  	"github.com/hyperledger/fabric/orderer/common/blockcutter"
    25  	"github.com/hyperledger/fabric/orderer/common/broadcast"
    26  	"github.com/hyperledger/fabric/orderer/common/configtxfilter"
    27  	"github.com/hyperledger/fabric/orderer/common/filter"
    28  	"github.com/hyperledger/fabric/orderer/common/sigfilter"
    29  	"github.com/hyperledger/fabric/orderer/common/sizefilter"
    30  	"github.com/hyperledger/fabric/orderer/ledger"
    31  	cb "github.com/hyperledger/fabric/protos/common"
    32  	"github.com/hyperledger/fabric/protos/utils"
    33  )
    34  
    35  // Consenter defines the backing ordering mechanism
    36  type Consenter interface {
    37  	// HandleChain should create and return a reference to a Chain for the given set of resources
    38  	// It will only be invoked for a given chain once per process.  In general, errors will be treated
    39  	// as irrecoverable and cause system shutdown.  See the description of Chain for more details
    40  	// The second argument to HandleChain is a pointer to the metadata stored on the `ORDERER` slot of
    41  	// the last block committed to the ledger of this Chain.  For a new chain, this metadata will be
    42  	// nil, as this field is not set on the genesis block
    43  	HandleChain(support ConsenterSupport, metadata *cb.Metadata) (Chain, error)
    44  }
    45  
    46  // Chain defines a way to inject messages for ordering
    47  // Note, that in order to allow flexibility in the implementation, it is the responsibility of the implementer
    48  // to take the ordered messages, send them through the blockcutter.Receiver supplied via HandleChain to cut blocks,
    49  // and ultimately write the ledger also supplied via HandleChain.  This flow allows for two primary flows
    50  // 1. Messages are ordered into a stream, the stream is cut into blocks, the blocks are committed (solo, kafka)
    51  // 2. Messages are cut into blocks, the blocks are ordered, then the blocks are committed (sbft)
    52  type Chain interface {
    53  	// Enqueue accepts a message and returns true on acceptance, or false on failure
    54  	Enqueue(env *cb.Envelope) bool
    55  
    56  	// Errored returns a channel which will close when an error has occurred
    57  	// This is especially useful for the Deliver client, who must terminate waiting
    58  	// clients when the consenter is not up to date
    59  	Errored() <-chan struct{}
    60  
    61  	// Start should allocate whatever resources are needed for staying up to date with the chain
    62  	// Typically, this involves creating a thread which reads from the ordering source, passes those
    63  	// messages to a block cutter, and writes the resulting blocks to the ledger
    64  	Start()
    65  
    66  	// Halt frees the resources which were allocated for this Chain
    67  	Halt()
    68  }
    69  
    70  // ConsenterSupport provides the resources available to a Consenter implementation
    71  type ConsenterSupport interface {
    72  	crypto.LocalSigner
    73  	BlockCutter() blockcutter.Receiver
    74  	SharedConfig() config.Orderer
    75  	CreateNextBlock(messages []*cb.Envelope) *cb.Block
    76  	WriteBlock(block *cb.Block, committers []filter.Committer, encodedMetadataValue []byte) *cb.Block
    77  	ChainID() string // ChainID returns the chain ID this specific consenter instance is associated with
    78  	Height() uint64  // Returns the number of blocks on the chain this specific consenter instance is associated with
    79  }
    80  
    81  // ChainSupport provides a wrapper for the resources backing a chain
    82  type ChainSupport interface {
    83  	// This interface is actually the union with the deliver.Support but because of a golang
    84  	// limitation https://github.com/golang/go/issues/6977 the methods must be explicitly declared
    85  
    86  	// PolicyManager returns the current policy manager as specified by the chain config
    87  	PolicyManager() policies.Manager
    88  
    89  	// Reader returns the chain Reader for the chain
    90  	Reader() ledger.Reader
    91  
    92  	// Errored returns whether the backing consenter has errored
    93  	Errored() <-chan struct{}
    94  
    95  	broadcast.Support
    96  	ConsenterSupport
    97  
    98  	// Sequence returns the current config sequence number
    99  	Sequence() uint64
   100  
   101  	// ProposeConfigUpdate applies a CONFIG_UPDATE to an existing config to produce a *cb.ConfigEnvelope
   102  	ProposeConfigUpdate(env *cb.Envelope) (*cb.ConfigEnvelope, error)
   103  }
   104  
   105  type chainSupport struct {
   106  	*ledgerResources
   107  	chain         Chain
   108  	cutter        blockcutter.Receiver
   109  	filters       *filter.RuleSet
   110  	signer        crypto.LocalSigner
   111  	lastConfig    uint64
   112  	lastConfigSeq uint64
   113  }
   114  
   115  func newChainSupport(
   116  	filters *filter.RuleSet,
   117  	ledgerResources *ledgerResources,
   118  	consenters map[string]Consenter,
   119  	signer crypto.LocalSigner,
   120  ) *chainSupport {
   121  
   122  	cutter := blockcutter.NewReceiverImpl(ledgerResources.SharedConfig(), filters)
   123  	consenterType := ledgerResources.SharedConfig().ConsensusType()
   124  	consenter, ok := consenters[consenterType]
   125  	if !ok {
   126  		logger.Fatalf("Error retrieving consenter of type: %s", consenterType)
   127  	}
   128  
   129  	cs := &chainSupport{
   130  		ledgerResources: ledgerResources,
   131  		cutter:          cutter,
   132  		filters:         filters,
   133  		signer:          signer,
   134  	}
   135  
   136  	cs.lastConfigSeq = cs.Sequence()
   137  
   138  	var err error
   139  
   140  	lastBlock := ledger.GetBlock(cs.Reader(), cs.Reader().Height()-1)
   141  
   142  	// If this is the genesis block, the lastconfig field may be empty, and, the last config is necessary 0
   143  	// so no need to initialize lastConfig
   144  	if lastBlock.Header.Number != 0 {
   145  		cs.lastConfig, err = utils.GetLastConfigIndexFromBlock(lastBlock)
   146  		if err != nil {
   147  			logger.Fatalf("[channel: %s] Error extracting last config block from block metadata: %s", cs.ChainID(), err)
   148  		}
   149  	}
   150  
   151  	metadata, err := utils.GetMetadataFromBlock(lastBlock, cb.BlockMetadataIndex_ORDERER)
   152  	// Assuming a block created with cb.NewBlock(), this should not
   153  	// error even if the orderer metadata is an empty byte slice
   154  	if err != nil {
   155  		logger.Fatalf("[channel: %s] Error extracting orderer metadata: %s", cs.ChainID(), err)
   156  	}
   157  	logger.Debugf("[channel: %s] Retrieved metadata for tip of chain (blockNumber=%d, lastConfig=%d, lastConfigSeq=%d): %+v", cs.ChainID(), lastBlock.Header.Number, cs.lastConfig, cs.lastConfigSeq, metadata)
   158  
   159  	cs.chain, err = consenter.HandleChain(cs, metadata)
   160  	if err != nil {
   161  		logger.Fatalf("[channel: %s] Error creating consenter: %s", cs.ChainID(), err)
   162  	}
   163  
   164  	return cs
   165  }
   166  
   167  // createStandardFilters creates the set of filters for a normal (non-system) chain
   168  func createStandardFilters(ledgerResources *ledgerResources) *filter.RuleSet {
   169  	return filter.NewRuleSet([]filter.Rule{
   170  		filter.EmptyRejectRule,
   171  		sizefilter.MaxBytesRule(ledgerResources.SharedConfig().BatchSize().AbsoluteMaxBytes),
   172  		sigfilter.New(policies.ChannelWriters, ledgerResources.PolicyManager()),
   173  		configtxfilter.NewFilter(ledgerResources),
   174  		filter.AcceptRule,
   175  	})
   176  
   177  }
   178  
   179  // createSystemChainFilters creates the set of filters for the ordering system chain
   180  func createSystemChainFilters(ml *multiLedger, ledgerResources *ledgerResources) *filter.RuleSet {
   181  	return filter.NewRuleSet([]filter.Rule{
   182  		filter.EmptyRejectRule,
   183  		sizefilter.MaxBytesRule(ledgerResources.SharedConfig().BatchSize().AbsoluteMaxBytes),
   184  		sigfilter.New(policies.ChannelWriters, ledgerResources.PolicyManager()),
   185  		newSystemChainFilter(ledgerResources, ml),
   186  		configtxfilter.NewFilter(ledgerResources),
   187  		filter.AcceptRule,
   188  	})
   189  }
   190  
   191  func (cs *chainSupport) start() {
   192  	cs.chain.Start()
   193  }
   194  
   195  func (cs *chainSupport) NewSignatureHeader() (*cb.SignatureHeader, error) {
   196  	return cs.signer.NewSignatureHeader()
   197  }
   198  
   199  func (cs *chainSupport) Sign(message []byte) ([]byte, error) {
   200  	return cs.signer.Sign(message)
   201  }
   202  
   203  func (cs *chainSupport) Filters() *filter.RuleSet {
   204  	return cs.filters
   205  }
   206  
   207  func (cs *chainSupport) BlockCutter() blockcutter.Receiver {
   208  	return cs.cutter
   209  }
   210  
   211  func (cs *chainSupport) Reader() ledger.Reader {
   212  	return cs.ledger
   213  }
   214  
   215  func (cs *chainSupport) Enqueue(env *cb.Envelope) bool {
   216  	return cs.chain.Enqueue(env)
   217  }
   218  
   219  func (cs *chainSupport) Errored() <-chan struct{} {
   220  	return cs.chain.Errored()
   221  }
   222  
   223  func (cs *chainSupport) CreateNextBlock(messages []*cb.Envelope) *cb.Block {
   224  	return ledger.CreateNextBlock(cs.ledger, messages)
   225  }
   226  
   227  func (cs *chainSupport) addBlockSignature(block *cb.Block) {
   228  	logger.Debugf("%+v", cs)
   229  	logger.Debugf("%+v", cs.signer)
   230  
   231  	blockSignature := &cb.MetadataSignature{
   232  		SignatureHeader: utils.MarshalOrPanic(utils.NewSignatureHeaderOrPanic(cs.signer)),
   233  	}
   234  
   235  	// Note, this value is intentionally nil, as this metadata is only about the signature, there is no additional metadata
   236  	// information required beyond the fact that the metadata item is signed.
   237  	blockSignatureValue := []byte(nil)
   238  
   239  	blockSignature.Signature = utils.SignOrPanic(cs.signer, util.ConcatenateBytes(blockSignatureValue, blockSignature.SignatureHeader, block.Header.Bytes()))
   240  
   241  	block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = utils.MarshalOrPanic(&cb.Metadata{
   242  		Value: blockSignatureValue,
   243  		Signatures: []*cb.MetadataSignature{
   244  			blockSignature,
   245  		},
   246  	})
   247  }
   248  
   249  func (cs *chainSupport) addLastConfigSignature(block *cb.Block) {
   250  	configSeq := cs.Sequence()
   251  	if configSeq > cs.lastConfigSeq {
   252  		logger.Debugf("[channel: %s] Detected lastConfigSeq transitioning from %d to %d, setting lastConfig from %d to %d", cs.ChainID(), cs.lastConfigSeq, configSeq, cs.lastConfig, block.Header.Number)
   253  		cs.lastConfig = block.Header.Number
   254  		cs.lastConfigSeq = configSeq
   255  	}
   256  
   257  	lastConfigSignature := &cb.MetadataSignature{
   258  		SignatureHeader: utils.MarshalOrPanic(utils.NewSignatureHeaderOrPanic(cs.signer)),
   259  	}
   260  
   261  	lastConfigValue := utils.MarshalOrPanic(&cb.LastConfig{Index: cs.lastConfig})
   262  	logger.Debugf("[channel: %s] About to write block, setting its LAST_CONFIG to %d", cs.ChainID(), cs.lastConfig)
   263  
   264  	lastConfigSignature.Signature = utils.SignOrPanic(cs.signer, util.ConcatenateBytes(lastConfigValue, lastConfigSignature.SignatureHeader, block.Header.Bytes()))
   265  
   266  	block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = utils.MarshalOrPanic(&cb.Metadata{
   267  		Value: lastConfigValue,
   268  		Signatures: []*cb.MetadataSignature{
   269  			lastConfigSignature,
   270  		},
   271  	})
   272  }
   273  
   274  func (cs *chainSupport) WriteBlock(block *cb.Block, committers []filter.Committer, encodedMetadataValue []byte) *cb.Block {
   275  	for _, committer := range committers {
   276  		committer.Commit()
   277  	}
   278  	// Set the orderer-related metadata field
   279  	if encodedMetadataValue != nil {
   280  		block.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER] = utils.MarshalOrPanic(&cb.Metadata{Value: encodedMetadataValue})
   281  	}
   282  	cs.addBlockSignature(block)
   283  	cs.addLastConfigSignature(block)
   284  
   285  	err := cs.ledger.Append(block)
   286  	if err != nil {
   287  		logger.Panicf("[channel: %s] Could not append block: %s", cs.ChainID(), err)
   288  	}
   289  	logger.Debugf("[channel: %s] Wrote block %d", cs.ChainID(), block.GetHeader().Number)
   290  
   291  	return block
   292  }
   293  
   294  func (cs *chainSupport) Height() uint64 {
   295  	return cs.Reader().Height()
   296  }