github.com/kaituanwang/hyperledger@v2.0.1+incompatible/orderer/consensus/etcdraft/util.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package etcdraft
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/x509"
    12  	"encoding/pem"
    13  	"time"
    14  
    15  	"github.com/golang/protobuf/proto"
    16  	"github.com/hyperledger/fabric-protos-go/common"
    17  	"github.com/hyperledger/fabric-protos-go/orderer"
    18  	"github.com/hyperledger/fabric-protos-go/orderer/etcdraft"
    19  	"github.com/hyperledger/fabric/bccsp"
    20  	"github.com/hyperledger/fabric/common/channelconfig"
    21  	"github.com/hyperledger/fabric/common/configtx"
    22  	"github.com/hyperledger/fabric/orderer/common/cluster"
    23  	"github.com/hyperledger/fabric/protoutil"
    24  	"github.com/pkg/errors"
    25  	"go.etcd.io/etcd/raft"
    26  	"go.etcd.io/etcd/raft/raftpb"
    27  )
    28  
    29  // RaftPeers maps consenters to slice of raft.Peer
    30  func RaftPeers(consenterIDs []uint64) []raft.Peer {
    31  	var peers []raft.Peer
    32  
    33  	for _, raftID := range consenterIDs {
    34  		peers = append(peers, raft.Peer{ID: raftID})
    35  	}
    36  	return peers
    37  }
    38  
    39  // ConsentersToMap maps consenters into set where key is client TLS certificate
    40  func ConsentersToMap(consenters []*etcdraft.Consenter) map[string]struct{} {
    41  	set := map[string]struct{}{}
    42  	for _, c := range consenters {
    43  		set[string(c.ClientTlsCert)] = struct{}{}
    44  	}
    45  	return set
    46  }
    47  
    48  // MetadataHasDuplication returns an error if the metadata has duplication of consenters.
    49  // A duplication is defined by having a server or a client TLS certificate that is found
    50  // in two different consenters, regardless of the type of certificate (client/server).
    51  func MetadataHasDuplication(md *etcdraft.ConfigMetadata) error {
    52  	if md == nil {
    53  		return errors.New("nil metadata")
    54  	}
    55  
    56  	for _, consenter := range md.Consenters {
    57  		if consenter == nil {
    58  			return errors.New("nil consenter in metadata")
    59  		}
    60  	}
    61  
    62  	seen := make(map[string]struct{})
    63  	for _, consenter := range md.Consenters {
    64  		serverKey := string(consenter.ServerTlsCert)
    65  		clientKey := string(consenter.ClientTlsCert)
    66  		_, duplicateServerCert := seen[serverKey]
    67  		_, duplicateClientCert := seen[clientKey]
    68  		if duplicateServerCert || duplicateClientCert {
    69  			return errors.Errorf("duplicate consenter: server cert: %s, client cert: %s", serverKey, clientKey)
    70  		}
    71  
    72  		seen[serverKey] = struct{}{}
    73  		seen[clientKey] = struct{}{}
    74  	}
    75  	return nil
    76  }
    77  
    78  // MetadataFromConfigValue reads and translates configuration updates from config value into raft metadata
    79  func MetadataFromConfigValue(configValue *common.ConfigValue) (*etcdraft.ConfigMetadata, error) {
    80  	consensusTypeValue := &orderer.ConsensusType{}
    81  	if err := proto.Unmarshal(configValue.Value, consensusTypeValue); err != nil {
    82  		return nil, errors.Wrap(err, "failed to unmarshal consensusType config update")
    83  	}
    84  
    85  	updatedMetadata := &etcdraft.ConfigMetadata{}
    86  	if err := proto.Unmarshal(consensusTypeValue.Metadata, updatedMetadata); err != nil {
    87  		return nil, errors.Wrap(err, "failed to unmarshal updated (new) etcdraft metadata configuration")
    88  	}
    89  
    90  	return updatedMetadata, nil
    91  }
    92  
    93  // MetadataFromConfigUpdate extracts consensus metadata from config update
    94  func MetadataFromConfigUpdate(update *common.ConfigUpdate) (*etcdraft.ConfigMetadata, error) {
    95  	var baseVersion uint64
    96  	if update.ReadSet != nil && update.ReadSet.Groups != nil {
    97  		if ordererConfigGroup, ok := update.ReadSet.Groups["Orderer"]; ok {
    98  			if val, ok := ordererConfigGroup.Values["ConsensusType"]; ok {
    99  				baseVersion = val.Version
   100  			}
   101  		}
   102  	}
   103  
   104  	if update.WriteSet != nil && update.WriteSet.Groups != nil {
   105  		if ordererConfigGroup, ok := update.WriteSet.Groups["Orderer"]; ok {
   106  			if val, ok := ordererConfigGroup.Values["ConsensusType"]; ok {
   107  				if baseVersion == val.Version {
   108  					// Only if the version in the write set differs from the read-set
   109  					// should we consider this to be an update to the consensus type
   110  					return nil, nil
   111  				}
   112  				return MetadataFromConfigValue(val)
   113  			}
   114  		}
   115  	}
   116  	return nil, nil
   117  }
   118  
   119  // ConfigChannelHeader expects a config block and returns the header type
   120  // of the config envelope wrapped in it, e.g. HeaderType_ORDERER_TRANSACTION
   121  func ConfigChannelHeader(block *common.Block) (hdr *common.ChannelHeader, err error) {
   122  	envelope, err := protoutil.ExtractEnvelope(block, 0)
   123  	if err != nil {
   124  		return nil, errors.Wrap(err, "failed to extract envelope from the block")
   125  	}
   126  
   127  	channelHeader, err := protoutil.ChannelHeader(envelope)
   128  	if err != nil {
   129  		return nil, errors.Wrap(err, "cannot extract channel header")
   130  	}
   131  
   132  	return channelHeader, nil
   133  }
   134  
   135  // ConfigEnvelopeFromBlock extracts configuration envelope from the block based on the
   136  // config type, i.e. HeaderType_ORDERER_TRANSACTION or HeaderType_CONFIG
   137  func ConfigEnvelopeFromBlock(block *common.Block) (*common.Envelope, error) {
   138  	if block == nil {
   139  		return nil, errors.New("nil block")
   140  	}
   141  
   142  	envelope, err := protoutil.ExtractEnvelope(block, 0)
   143  	if err != nil {
   144  		return nil, errors.Wrapf(err, "failed to extract envelope from the block")
   145  	}
   146  
   147  	channelHeader, err := protoutil.ChannelHeader(envelope)
   148  	if err != nil {
   149  		return nil, errors.Wrap(err, "cannot extract channel header")
   150  	}
   151  
   152  	switch channelHeader.Type {
   153  	case int32(common.HeaderType_ORDERER_TRANSACTION):
   154  		payload, err := protoutil.UnmarshalPayload(envelope.Payload)
   155  		if err != nil {
   156  			return nil, errors.Wrap(err, "failed to unmarshal envelope to extract config payload for orderer transaction")
   157  		}
   158  		configEnvelop, err := protoutil.UnmarshalEnvelope(payload.Data)
   159  		if err != nil {
   160  			return nil, errors.Wrap(err, "failed to unmarshal config envelope for orderer type transaction")
   161  		}
   162  
   163  		return configEnvelop, nil
   164  	case int32(common.HeaderType_CONFIG):
   165  		return envelope, nil
   166  	default:
   167  		return nil, errors.Errorf("unexpected header type: %v", channelHeader.Type)
   168  	}
   169  }
   170  
   171  // ConsensusMetadataFromConfigBlock reads consensus metadata updates from the configuration block
   172  func ConsensusMetadataFromConfigBlock(block *common.Block) (*etcdraft.ConfigMetadata, error) {
   173  	if block == nil {
   174  		return nil, errors.New("nil block")
   175  	}
   176  
   177  	if !protoutil.IsConfigBlock(block) {
   178  		return nil, errors.New("not a config block")
   179  	}
   180  
   181  	configEnvelope, err := ConfigEnvelopeFromBlock(block)
   182  	if err != nil {
   183  		return nil, errors.Wrap(err, "cannot read config update")
   184  	}
   185  
   186  	payload, err := protoutil.UnmarshalPayload(configEnvelope.Payload)
   187  	if err != nil {
   188  		return nil, errors.Wrap(err, "failed to extract payload from config envelope")
   189  	}
   190  	// get config update
   191  	configUpdate, err := configtx.UnmarshalConfigUpdateFromPayload(payload)
   192  	if err != nil {
   193  		return nil, errors.Wrap(err, "could not read config update")
   194  	}
   195  
   196  	return MetadataFromConfigUpdate(configUpdate)
   197  }
   198  
   199  // CheckConfigMetadata validates Raft config metadata
   200  func CheckConfigMetadata(metadata *etcdraft.ConfigMetadata) error {
   201  	if metadata == nil {
   202  		// defensive check. this should not happen as CheckConfigMetadata
   203  		// should always be called with non-nil config metadata
   204  		return errors.Errorf("nil Raft config metadata")
   205  	}
   206  
   207  	if metadata.Options.HeartbeatTick == 0 ||
   208  		metadata.Options.ElectionTick == 0 ||
   209  		metadata.Options.MaxInflightBlocks == 0 {
   210  		// if SnapshotIntervalSize is zero, DefaultSnapshotIntervalSize is used
   211  		return errors.Errorf("none of HeartbeatTick (%d), ElectionTick (%d) and MaxInflightBlocks (%d) can be zero",
   212  			metadata.Options.HeartbeatTick, metadata.Options.ElectionTick, metadata.Options.MaxInflightBlocks)
   213  	}
   214  
   215  	// check Raft options
   216  	if metadata.Options.ElectionTick <= metadata.Options.HeartbeatTick {
   217  		return errors.Errorf("ElectionTick (%d) must be greater than HeartbeatTick (%d)",
   218  			metadata.Options.HeartbeatTick, metadata.Options.HeartbeatTick)
   219  	}
   220  
   221  	if d, err := time.ParseDuration(metadata.Options.TickInterval); err != nil {
   222  		return errors.Errorf("failed to parse TickInterval (%s) to time duration: %s", metadata.Options.TickInterval, err)
   223  	} else if d == 0 {
   224  		return errors.Errorf("TickInterval cannot be zero")
   225  	}
   226  
   227  	if len(metadata.Consenters) == 0 {
   228  		return errors.Errorf("empty consenter set")
   229  	}
   230  
   231  	// sanity check of certificates
   232  	for _, consenter := range metadata.Consenters {
   233  		if consenter == nil {
   234  			return errors.Errorf("metadata has nil consenter")
   235  		}
   236  		if err := validateCert(consenter.ServerTlsCert, "server"); err != nil {
   237  			return err
   238  		}
   239  		if err := validateCert(consenter.ClientTlsCert, "client"); err != nil {
   240  			return err
   241  		}
   242  	}
   243  
   244  	if err := MetadataHasDuplication(metadata); err != nil {
   245  		return err
   246  	}
   247  
   248  	return nil
   249  }
   250  
   251  func validateCert(pemData []byte, certRole string) error {
   252  	bl, _ := pem.Decode(pemData)
   253  
   254  	if bl == nil {
   255  		return errors.Errorf("%s TLS certificate is not PEM encoded: %s", certRole, string(pemData))
   256  	}
   257  
   258  	if _, err := x509.ParseCertificate(bl.Bytes); err != nil {
   259  		return errors.Errorf("%s TLS certificate has invalid ASN1 structure, %v: %s", certRole, err, string(pemData))
   260  	}
   261  	return nil
   262  }
   263  
   264  // ConsenterCertificate denotes a TLS certificate of a consenter
   265  type ConsenterCertificate struct {
   266  	ConsenterCertificate []byte
   267  	CryptoProvider       bccsp.BCCSP
   268  }
   269  
   270  // type ConsenterCertificate []byte
   271  
   272  // IsConsenterOfChannel returns whether the caller is a consenter of a channel
   273  // by inspecting the given configuration block.
   274  // It returns nil if true, else returns an error.
   275  func (conCert ConsenterCertificate) IsConsenterOfChannel(configBlock *common.Block) error {
   276  	if configBlock == nil {
   277  		return errors.New("nil block")
   278  	}
   279  	envelopeConfig, err := protoutil.ExtractEnvelope(configBlock, 0)
   280  	if err != nil {
   281  		return err
   282  	}
   283  	bundle, err := channelconfig.NewBundleFromEnvelope(envelopeConfig, conCert.CryptoProvider)
   284  	if err != nil {
   285  		return err
   286  	}
   287  	oc, exists := bundle.OrdererConfig()
   288  	if !exists {
   289  		return errors.New("no orderer config in bundle")
   290  	}
   291  	m := &etcdraft.ConfigMetadata{}
   292  	if err := proto.Unmarshal(oc.ConsensusMetadata(), m); err != nil {
   293  		return err
   294  	}
   295  
   296  	for _, consenter := range m.Consenters {
   297  		if bytes.Equal(conCert.ConsenterCertificate, consenter.ServerTlsCert) || bytes.Equal(conCert.ConsenterCertificate, consenter.ClientTlsCert) {
   298  			return nil
   299  		}
   300  	}
   301  	return cluster.ErrNotInChannel
   302  }
   303  
   304  // NodeExists returns trues if node id exists in the slice
   305  // and false otherwise
   306  func NodeExists(id uint64, nodes []uint64) bool {
   307  	for _, nodeID := range nodes {
   308  		if nodeID == id {
   309  			return true
   310  		}
   311  	}
   312  	return false
   313  }
   314  
   315  // ConfChange computes Raft configuration changes based on current Raft
   316  // configuration state and consenters IDs stored in RaftMetadata.
   317  func ConfChange(blockMetadata *etcdraft.BlockMetadata, confState *raftpb.ConfState) *raftpb.ConfChange {
   318  	raftConfChange := &raftpb.ConfChange{}
   319  
   320  	// need to compute conf changes to propose
   321  	if len(confState.Nodes) < len(blockMetadata.ConsenterIds) {
   322  		// adding new node
   323  		raftConfChange.Type = raftpb.ConfChangeAddNode
   324  		for _, consenterID := range blockMetadata.ConsenterIds {
   325  			if NodeExists(consenterID, confState.Nodes) {
   326  				continue
   327  			}
   328  			raftConfChange.NodeID = consenterID
   329  		}
   330  	} else {
   331  		// removing node
   332  		raftConfChange.Type = raftpb.ConfChangeRemoveNode
   333  		for _, nodeID := range confState.Nodes {
   334  			if NodeExists(nodeID, blockMetadata.ConsenterIds) {
   335  				continue
   336  			}
   337  			raftConfChange.NodeID = nodeID
   338  		}
   339  	}
   340  
   341  	return raftConfChange
   342  }
   343  
   344  // CreateConsentersMap creates a map of Raft Node IDs to Consenter given the block metadata and the config metadata.
   345  func CreateConsentersMap(blockMetadata *etcdraft.BlockMetadata, configMetadata *etcdraft.ConfigMetadata) map[uint64]*etcdraft.Consenter {
   346  	consenters := map[uint64]*etcdraft.Consenter{}
   347  	for i, consenter := range configMetadata.Consenters {
   348  		consenters[blockMetadata.ConsenterIds[i]] = consenter
   349  	}
   350  	return consenters
   351  }