github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/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/inklabsfoundation/inkchain/common/config"
    21  	"github.com/inklabsfoundation/inkchain/common/crypto"
    22  	"github.com/inklabsfoundation/inkchain/common/policies"
    23  	"github.com/inklabsfoundation/inkchain/common/util"
    24  	"github.com/inklabsfoundation/inkchain/orderer/common/blockcutter"
    25  	"github.com/inklabsfoundation/inkchain/orderer/common/broadcast"
    26  	"github.com/inklabsfoundation/inkchain/orderer/common/configtxfilter"
    27  	"github.com/inklabsfoundation/inkchain/orderer/common/filter"
    28  	"github.com/inklabsfoundation/inkchain/orderer/common/sigfilter"
    29  	"github.com/inklabsfoundation/inkchain/orderer/common/sizefilter"
    30  	"github.com/inklabsfoundation/inkchain/orderer/ledger"
    31  	cb "github.com/inklabsfoundation/inkchain/protos/common"
    32  	"github.com/inklabsfoundation/inkchain/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  	feeAddress    string
   114  	blockVersion  uint64
   115  }
   116  
   117  func newChainSupport(
   118  	filters *filter.RuleSet,
   119  	ledgerResources *ledgerResources,
   120  	consenters map[string]Consenter,
   121  	signer crypto.LocalSigner,
   122  	feeAddress string,
   123  	blockVersion uint64,
   124  ) *chainSupport {
   125  
   126  	cutter := blockcutter.NewReceiverImpl(ledgerResources.SharedConfig(), filters)
   127  	consenterType := ledgerResources.SharedConfig().ConsensusType()
   128  	consenter, ok := consenters[consenterType]
   129  	if !ok {
   130  		logger.Fatalf("Error retrieving consenter of type: %s", consenterType)
   131  	}
   132  
   133  	cs := &chainSupport{
   134  		ledgerResources: ledgerResources,
   135  		cutter:          cutter,
   136  		filters:         filters,
   137  		signer:          signer,
   138  		feeAddress:      feeAddress,
   139  		blockVersion:    blockVersion,
   140  	}
   141  
   142  	cs.lastConfigSeq = cs.Sequence()
   143  
   144  	var err error
   145  
   146  	lastBlock := ledger.GetBlock(cs.Reader(), cs.Reader().Height()-1)
   147  
   148  	// If this is the genesis block, the lastconfig field may be empty, and, the last config is necessary 0
   149  	// so no need to initialize lastConfig
   150  	if lastBlock.Header.Number != 0 {
   151  		cs.lastConfig, err = utils.GetLastConfigIndexFromBlock(lastBlock)
   152  		if err != nil {
   153  			logger.Fatalf("[channel: %s] Error extracting last config block from block metadata: %s", cs.ChainID(), err)
   154  		}
   155  	}
   156  
   157  	metadata, err := utils.GetMetadataFromBlock(lastBlock, cb.BlockMetadataIndex_ORDERER)
   158  	// Assuming a block created with cb.NewBlock(), this should not
   159  	// error even if the orderer metadata is an empty byte slice
   160  	if err != nil {
   161  		logger.Fatalf("[channel: %s] Error extracting orderer metadata: %s", cs.ChainID(), err)
   162  	}
   163  	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)
   164  
   165  	cs.chain, err = consenter.HandleChain(cs, metadata)
   166  	if err != nil {
   167  		logger.Fatalf("[channel: %s] Error creating consenter: %s", cs.ChainID(), err)
   168  	}
   169  
   170  	return cs
   171  }
   172  
   173  // createStandardFilters creates the set of filters for a normal (non-system) chain
   174  func createStandardFilters(ledgerResources *ledgerResources) *filter.RuleSet {
   175  	return filter.NewRuleSet([]filter.Rule{
   176  		filter.EmptyRejectRule,
   177  		sizefilter.MaxBytesRule(ledgerResources.SharedConfig()),
   178  		sigfilter.New(policies.ChannelWriters, ledgerResources.PolicyManager()),
   179  		configtxfilter.NewFilter(ledgerResources),
   180  		filter.AcceptRule,
   181  	})
   182  }
   183  
   184  // createSystemChainFilters creates the set of filters for the ordering system chain
   185  func createSystemChainFilters(ml *multiLedger, ledgerResources *ledgerResources) *filter.RuleSet {
   186  	return filter.NewRuleSet([]filter.Rule{
   187  		filter.EmptyRejectRule,
   188  		sizefilter.MaxBytesRule(ledgerResources.SharedConfig()),
   189  		sigfilter.New(policies.ChannelWriters, ledgerResources.PolicyManager()),
   190  		newSystemChainFilter(ledgerResources, ml),
   191  		configtxfilter.NewFilter(ledgerResources),
   192  		filter.AcceptRule,
   193  	})
   194  }
   195  
   196  func (cs *chainSupport) start() {
   197  	cs.chain.Start()
   198  }
   199  
   200  func (cs *chainSupport) NewSignatureHeader() (*cb.SignatureHeader, error) {
   201  	return cs.signer.NewSignatureHeader()
   202  }
   203  
   204  func (cs *chainSupport) Sign(message []byte) ([]byte, error) {
   205  	return cs.signer.Sign(message)
   206  }
   207  
   208  func (cs *chainSupport) Filters() *filter.RuleSet {
   209  	return cs.filters
   210  }
   211  
   212  func (cs *chainSupport) BlockCutter() blockcutter.Receiver {
   213  	return cs.cutter
   214  }
   215  
   216  func (cs *chainSupport) Reader() ledger.Reader {
   217  	return cs.ledger
   218  }
   219  
   220  func (cs *chainSupport) Enqueue(env *cb.Envelope) bool {
   221  	return cs.chain.Enqueue(env)
   222  }
   223  
   224  func (cs *chainSupport) Errored() <-chan struct{} {
   225  	return cs.chain.Errored()
   226  }
   227  
   228  func (cs *chainSupport) CreateNextBlock(messages []*cb.Envelope) *cb.Block {
   229  	return ledger.CreateNextBlock(cs.ledger, messages, cs.feeAddress, cs.blockVersion)
   230  }
   231  
   232  func (cs *chainSupport) addBlockSignature(block *cb.Block) {
   233  	logger.Debugf("%+v", cs)
   234  	logger.Debugf("%+v", cs.signer)
   235  
   236  	blockSignature := &cb.MetadataSignature{
   237  		SignatureHeader: utils.MarshalOrPanic(utils.NewSignatureHeaderOrPanic(cs.signer)),
   238  	}
   239  
   240  	// Note, this value is intentionally nil, as this metadata is only about the signature, there is no additional metadata
   241  	// information required beyond the fact that the metadata item is signed.
   242  	blockSignatureValue := []byte(nil)
   243  
   244  	blockSignature.Signature = utils.SignOrPanic(cs.signer, util.ConcatenateBytes(blockSignatureValue, blockSignature.SignatureHeader, block.Header.Bytes()))
   245  
   246  	block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = utils.MarshalOrPanic(&cb.Metadata{
   247  		Value: blockSignatureValue,
   248  		Signatures: []*cb.MetadataSignature{
   249  			blockSignature,
   250  		},
   251  	})
   252  }
   253  
   254  func (cs *chainSupport) addLastConfigSignature(block *cb.Block) {
   255  	configSeq := cs.Sequence()
   256  	if configSeq > cs.lastConfigSeq {
   257  		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)
   258  		cs.lastConfig = block.Header.Number
   259  		cs.lastConfigSeq = configSeq
   260  	}
   261  
   262  	lastConfigSignature := &cb.MetadataSignature{
   263  		SignatureHeader: utils.MarshalOrPanic(utils.NewSignatureHeaderOrPanic(cs.signer)),
   264  	}
   265  
   266  	lastConfigValue := utils.MarshalOrPanic(&cb.LastConfig{Index: cs.lastConfig})
   267  	logger.Debugf("[channel: %s] About to write block, setting its LAST_CONFIG to %d", cs.ChainID(), cs.lastConfig)
   268  
   269  	lastConfigSignature.Signature = utils.SignOrPanic(cs.signer, util.ConcatenateBytes(lastConfigValue, lastConfigSignature.SignatureHeader, block.Header.Bytes()))
   270  
   271  	block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = utils.MarshalOrPanic(&cb.Metadata{
   272  		Value: lastConfigValue,
   273  		Signatures: []*cb.MetadataSignature{
   274  			lastConfigSignature,
   275  		},
   276  	})
   277  }
   278  
   279  func (cs *chainSupport) WriteBlock(block *cb.Block, committers []filter.Committer, encodedMetadataValue []byte) *cb.Block {
   280  	for _, committer := range committers {
   281  		committer.Commit()
   282  	}
   283  	// Set the orderer-related metadata field
   284  	if encodedMetadataValue != nil {
   285  		block.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER] = utils.MarshalOrPanic(&cb.Metadata{Value: encodedMetadataValue})
   286  	}
   287  	cs.addBlockSignature(block)
   288  	cs.addLastConfigSignature(block)
   289  
   290  	err := cs.ledger.Append(block)
   291  	if err != nil {
   292  		logger.Panicf("[channel: %s] Could not append block: %s", cs.ChainID(), err)
   293  	}
   294  	logger.Debugf("[channel: %s] Wrote block %d", cs.ChainID(), block.GetHeader().Number)
   295  
   296  	return block
   297  }
   298  
   299  func (cs *chainSupport) Height() uint64 {
   300  	return cs.Reader().Height()
   301  }