func (cbs *commonBootstrapper) encodeBatchSize() *cb.SignedConfigurationItem { configItemKey := sharedconfig.BatchSizeKey configItemValue := utils.MarshalOrPanic(&ab.BatchSize{Messages: cbs.batchSize}) modPolicy := configtx.DefaultModificationPolicyID configItemChainHeader := utils.MakeChainHeader(cb.HeaderType_CONFIGURATION_ITEM, msgVersion, cbs.chainID, epoch) configItem := utils.MakeConfigurationItem(configItemChainHeader, cb.ConfigurationItem_Orderer, lastModified, modPolicy, configItemKey, configItemValue) return &cb.SignedConfigurationItem{ConfigurationItem: utils.MarshalOrPanic(configItem), Signatures: nil} }
func (kbs *kafkaBootstrapper) encodeKafkaBrokers() *cb.SignedConfigurationItem { configItemKey := sharedconfig.KafkaBrokersKey configItemValue := utils.MarshalOrPanic(&ab.KafkaBrokers{Brokers: kbs.kafkaBrokers}) modPolicy := configtx.DefaultModificationPolicyID configItemChainHeader := utils.MakeChainHeader(cb.HeaderType_CONFIGURATION_ITEM, msgVersion, kbs.chainID, epoch) configItem := utils.MakeConfigurationItem(configItemChainHeader, cb.ConfigurationItem_Orderer, lastModified, modPolicy, configItemKey, configItemValue) return &cb.SignedConfigurationItem{ConfigurationItem: utils.MarshalOrPanic(configItem), Signatures: nil} }
func (cbs *commonBootstrapper) encodeAcceptAllPolicy() *cb.SignedConfigurationItem { configItemKey := AcceptAllPolicyKey configItemValue := utils.MarshalOrPanic(utils.MakePolicyOrPanic(cauthdsl.AcceptAllPolicy)) modPolicy := configtx.DefaultModificationPolicyID configItemChainHeader := utils.MakeChainHeader(cb.HeaderType_CONFIGURATION_ITEM, msgVersion, cbs.chainID, epoch) configItem := utils.MakeConfigurationItem(configItemChainHeader, cb.ConfigurationItem_Policy, lastModified, modPolicy, configItemKey, configItemValue) return &cb.SignedConfigurationItem{ConfigurationItem: utils.MarshalOrPanic(configItem), Signatures: nil} }
func (cbs *commonBootstrapper) lockDefaultModificationPolicy() *cb.SignedConfigurationItem { // Lock down the default modification policy to prevent any further policy modifications configItemKey := configtx.DefaultModificationPolicyID configItemValue := utils.MarshalOrPanic(utils.MakePolicyOrPanic(cauthdsl.RejectAllPolicy)) modPolicy := configtx.DefaultModificationPolicyID configItemChainHeader := utils.MakeChainHeader(cb.HeaderType_CONFIGURATION_ITEM, msgVersion, cbs.chainID, epoch) configItem := utils.MakeConfigurationItem(configItemChainHeader, cb.ConfigurationItem_Policy, lastModified, modPolicy, configItemKey, configItemValue) return &cb.SignedConfigurationItem{ConfigurationItem: utils.MarshalOrPanic(configItem), Signatures: nil} }
// Enqueue accepts a message and returns true on acceptance, or false on shutdown. // Implements the multichain.Chain interface. Called by the drainQueue goroutine, // which is spawned when the broadcast handler's Handle() function is invoked. func (ch *chainImpl) Enqueue(env *cb.Envelope) bool { if ch.halted { return false } logger.Debug("Enqueueing:", env) if err := ch.producer.Send(ch.partition, utils.MarshalOrPanic(newRegularMessage(utils.MarshalOrPanic(env)))); err != nil { logger.Errorf("Couldn't post to %s: %s", ch.partition, err) return false } return !ch.halted // If ch.halted has been set to true while sending, we should return false }
func makeConfigMessage(chainID string) *cb.Envelope { payload := &cb.Payload{ Data: utils.MarshalOrPanic(&cb.ConfigurationEnvelope{}), Header: &cb.Header{ ChainHeader: &cb.ChainHeader{ ChainID: chainID, Type: int32(cb.HeaderType_CONFIGURATION_TRANSACTION), }, }, } return &cb.Envelope{ Payload: utils.MarshalOrPanic(payload), } }
func TestConsensusType(t *testing.T) { endType := "foo" invalidMessage := &cb.ConfigurationItem{ Type: cb.ConfigurationItem_Orderer, Key: ConsensusTypeKey, Value: []byte("Garbage Data"), } validMessage := &cb.ConfigurationItem{ Type: cb.ConfigurationItem_Orderer, Key: ConsensusTypeKey, Value: utils.MarshalOrPanic(&ab.ConsensusType{Type: endType}), } otherValidMessage := &cb.ConfigurationItem{ Type: cb.ConfigurationItem_Orderer, Key: ConsensusTypeKey, Value: utils.MarshalOrPanic(&ab.ConsensusType{Type: "bar"}), } m := NewManagerImpl() m.BeginConfig() err := m.ProposeConfig(validMessage) if err != nil { t.Fatalf("Error applying valid config: %s", err) } m.CommitConfig() m.BeginConfig() err = m.ProposeConfig(invalidMessage) if err == nil { t.Fatalf("Should have failed on invalid message") } err = m.ProposeConfig(validMessage) if err != nil { t.Fatalf("Error re-applying valid config: %s", err) } err = m.ProposeConfig(otherValidMessage) if err == nil { t.Fatalf("Should not have applied config with different consensus type after it was initially set") } m.CommitConfig() if nowType := m.ConsensusType(); nowType != endType { t.Fatalf("Consensus type should have ended as %s but was %s", endType, nowType) } }
func TestGoodProposal(t *testing.T) { newChainID := "NewChainID" mcc := newMockChainCreator() mcc.ms.msc.chainCreators = []string{provisional.AcceptAllPolicyKey} mcc.ms.mpm.mp = &mockPolicy{} chainCreateTx := &cb.ConfigurationItem{ Header: &cb.ChainHeader{ ChainID: newChainID, Type: int32(cb.HeaderType_CONFIGURATION_ITEM), }, Key: utils.CreationPolicyKey, Type: cb.ConfigurationItem_Orderer, Value: utils.MarshalOrPanic(&ab.CreationPolicy{ Policy: provisional.AcceptAllPolicyKey, Digest: coreutil.ComputeCryptoHash([]byte{}), }), } ingressTx := makeConfigTxWithItems(newChainID, chainCreateTx) status := mcc.sysChain.proposeChain(ingressTx) if status != cb.Status_SUCCESS { t.Fatalf("Should have successfully proposed chain") } expected := 1 if len(mcc.ms.queue) != expected { t.Fatalf("Expected %d creation txs in the chain, but found %d", expected, len(mcc.ms.queue)) } wrapped := mcc.ms.queue[0] payload := utils.UnmarshalPayloadOrPanic(wrapped.Payload) if payload.Header.ChainHeader.Type != int32(cb.HeaderType_ORDERER_TRANSACTION) { t.Fatalf("Wrapped transaction should be of type ORDERER_TRANSACTION") } envelope := utils.UnmarshalEnvelopeOrPanic(payload.Data) if !reflect.DeepEqual(envelope, ingressTx) { t.Fatalf("Received different configtx than ingressed into the system") } sysFilter := newSystemChainFilter(mcc) action, committer := sysFilter.Apply(wrapped) if action != filter.Accept { t.Fatalf("Should have accepted the transaction, as it was already validated") } if !committer.Isolated() { t.Fatalf("Chain creation transactions should be isolated on commit") } committer.Commit() if len(mcc.newChains) != 1 { t.Fatalf("Proposal should only have created 1 new chain") } if !reflect.DeepEqual(mcc.newChains[0], ingressTx) { t.Fatalf("New chain should have been created with ingressTx") } }
// Start allocates the necessary resources for staying up to date with this Chain. // Implements the multichain.Chain interface. Called by multichain.NewManagerImpl() // which is invoked when the ordering process is launched, before the call to NewServer(). func (ch *chainImpl) Start() { // 1. Post the CONNECT message to prevent panicking that occurs // when seeking on a partition that hasn't been created yet. logger.Debug("Posting the CONNECT message...") if err := ch.producer.Send(ch.partition, utils.MarshalOrPanic(newConnectMessage())); err != nil { logger.Criticalf("Couldn't post CONNECT message to %s: %s", ch.partition, err) close(ch.exitChan) ch.halted = true return } // 2. Set up the listener/consumer for this partition. // TODO When restart support gets added to the common components level, start // the consumer from lastProcessed. For now, hard-code to oldest available. consumer, err := ch.consenter.consFunc()(ch.support.SharedConfig().KafkaBrokers(), ch.consenter.kafkaVersion(), ch.partition, ch.lastProcessed+1) if err != nil { logger.Criticalf("Cannot retrieve required offset from Kafka cluster for chain %s: %s", ch.partition, err) close(ch.exitChan) ch.halted = true return } ch.consumer = consumer // 3. Set the loop the keep up to date with the chain. go ch.loop() }
func testNewConsumerMessage(cp ChainPartition, offset int64, kafkaMessage *ab.KafkaMessage) *sarama.ConsumerMessage { return &sarama.ConsumerMessage{ Value: sarama.ByteEncoder(utils.MarshalOrPanic(kafkaMessage)), Topic: cp.Topic(), Partition: cp.Partition(), Offset: offset, } }
func (mc *mockConsumerImpl) testFillWithBlocks(offset int64) { for i := int64(1); i <= offset; i++ { go func() { mc.disk <- newRegularMessage(utils.MarshalOrPanic(newTestEnvelope(fmt.Sprintf("consumer fill-in %d", i)))) }() <-mc.Recv() } return }
func mockConfigBlock() []byte { var blockBytes []byte block, err := utils.MakeConfigurationBlock("mytestchainid") if err != nil { blockBytes = nil } else { blockBytes = utils.MarshalOrPanic(block) } return blockBytes }
func (cbs *commonBootstrapper) makeGenesisBlock(configEnvelope *cb.ConfigurationEnvelope) *cb.Block { configItemChainHeader := utils.MakeChainHeader(cb.HeaderType_CONFIGURATION_ITEM, msgVersion, cbs.chainID, epoch) payloadChainHeader := utils.MakeChainHeader(cb.HeaderType_CONFIGURATION_TRANSACTION, configItemChainHeader.Version, cbs.chainID, epoch) payloadSignatureHeader := utils.MakeSignatureHeader(nil, utils.CreateNonceOrPanic()) payloadHeader := utils.MakePayloadHeader(payloadChainHeader, payloadSignatureHeader) payload := &cb.Payload{Header: payloadHeader, Data: utils.MarshalOrPanic(configEnvelope)} envelope := &cb.Envelope{Payload: utils.MarshalOrPanic(payload), Signature: nil} blockData := &cb.BlockData{Data: [][]byte{utils.MarshalOrPanic(envelope)}} return &cb.Block{ Header: &cb.BlockHeader{ Number: 0, PreviousHash: nil, DataHash: blockData.Hash(), }, Data: blockData, Metadata: nil, } }
func TestBatchSize(t *testing.T) { endBatchSize := uint32(10) invalidMessage := &cb.ConfigurationItem{ Type: cb.ConfigurationItem_Orderer, Key: BatchSizeKey, Value: []byte("Garbage Data"), } zeroBatchSize := &cb.ConfigurationItem{ Type: cb.ConfigurationItem_Orderer, Key: BatchSizeKey, Value: utils.MarshalOrPanic(&ab.BatchSize{Messages: 0}), } validMessage := &cb.ConfigurationItem{ Type: cb.ConfigurationItem_Orderer, Key: BatchSizeKey, Value: utils.MarshalOrPanic(&ab.BatchSize{Messages: endBatchSize}), } m := NewManagerImpl() m.BeginConfig() err := m.ProposeConfig(validMessage) if err != nil { t.Fatalf("Error applying valid config: %s", err) } err = m.ProposeConfig(invalidMessage) if err == nil { t.Fatalf("Should have failed on invalid message") } err = m.ProposeConfig(zeroBatchSize) if err == nil { t.Fatalf("Should have rejected batch size of 0") } m.CommitConfig() if nowBatchSize := m.BatchSize(); nowBatchSize != endBatchSize { t.Fatalf("Got batch size of %d when expecting batch size of %d", nowBatchSize, endBatchSize) } }
func makeMessage(chainID string, data []byte) *cb.Envelope { payload := &cb.Payload{ Data: data, Header: &cb.Header{ ChainHeader: &cb.ChainHeader{ ChainID: chainID, }, }, } return &cb.Envelope{ Payload: utils.MarshalOrPanic(payload), } }
func TestProducerSend(t *testing.T) { cp := newChainPartition(provisional.TestChainID, rawPartition) mp := mockNewProducer(t, cp, testMiddleOffset, make(chan *ab.KafkaMessage)) defer testClose(t, mp) go func() { <-mp.(*mockProducerImpl).disk // Retrieve the message that we'll be sending below }() if err := mp.Send(cp, utils.MarshalOrPanic(newRegularMessage([]byte("foo")))); err != nil { t.Fatalf("Mock producer was not initialized correctly: %s", err) } }
func makeConfigTxWithItems(chainID string, items ...*cb.ConfigurationItem) *cb.Envelope { signedItems := make([]*cb.SignedConfigurationItem, len(items)) for i, item := range items { signedItems[i] = &cb.SignedConfigurationItem{ ConfigurationItem: utils.MarshalOrPanic(item), } } payload := &cb.Payload{ Header: &cb.Header{ ChainHeader: &cb.ChainHeader{ Type: int32(cb.HeaderType_CONFIGURATION_TRANSACTION), ChainID: chainID, }, }, Data: utils.MarshalOrPanic(&cb.ConfigurationEnvelope{ Items: signedItems, }), } return &cb.Envelope{ Payload: utils.MarshalOrPanic(payload), } }
// TODO move to util func makeNormalTx(chainID string, i int) *cb.Envelope { payload := &cb.Payload{ Header: &cb.Header{ ChainHeader: &cb.ChainHeader{ Type: int32(cb.HeaderType_ENDORSER_TRANSACTION), ChainID: chainID, }, }, Data: []byte(fmt.Sprintf("%d", i)), } return &cb.Envelope{ Payload: utils.MarshalOrPanic(payload), } }
func (mp *mockProducerImpl) testFillWithBlocks(cp ChainPartition, offset int64) { dieChan := make(chan struct{}) deadChan := make(chan struct{}) go func() { // This goroutine is meant to read only the "fill-in" blocks for { select { case <-mp.disk: case <-dieChan: close(deadChan) return } } }() for i := int64(1); i <= offset; i++ { mp.Send(cp, utils.MarshalOrPanic(newRegularMessage(utils.MarshalOrPanic(newTestEnvelope(fmt.Sprintf("producer fill-in %d", i)))))) } close(dieChan) <-deadChan return }
func TestProposalWithMissingPolicy(t *testing.T) { newChainID := "NewChainID" mcc := newMockChainCreator() mcc.ms.msc.chainCreators = []string{provisional.AcceptAllPolicyKey} chainCreateTx := &cb.ConfigurationItem{ Key: utils.CreationPolicyKey, Type: cb.ConfigurationItem_Orderer, Value: utils.MarshalOrPanic(&ab.CreationPolicy{ Policy: provisional.AcceptAllPolicyKey, Digest: coreutil.ComputeCryptoHash([]byte{}), }), } ingressTx := makeConfigTxWithItems(newChainID, chainCreateTx) status := mcc.sysChain.proposeChain(ingressTx) if status == cb.Status_SUCCESS { t.Fatalf("Should not have validated the transaction with missing policy") } }
func TestKafkaBrokers(t *testing.T) { endList := []string{"127.0.0.1:9092", "foo.bar:9092"} invalidMessage := &cb.ConfigurationItem{ Type: cb.ConfigurationItem_Orderer, Key: KafkaBrokersKey, Value: []byte("Garbage Data"), } zeroBrokers := &cb.ConfigurationItem{ Type: cb.ConfigurationItem_Orderer, Key: KafkaBrokersKey, Value: utils.MarshalOrPanic(&ab.KafkaBrokers{}), } badList := []string{"127.0.0.1", "foo.bar", "127.0.0.1:-1", "localhost:65536", "foo.bar.:9092", ".127.0.0.1:9092", "-foo.bar:9092"} badMessages := []*cb.ConfigurationItem{} for _, badAddress := range badList { msg := &cb.ConfigurationItem{ Type: cb.ConfigurationItem_Orderer, Key: KafkaBrokersKey, Value: utils.MarshalOrPanic(&ab.KafkaBrokers{Brokers: []string{badAddress}}), } badMessages = append(badMessages, msg) } validMessage := &cb.ConfigurationItem{ Type: cb.ConfigurationItem_Orderer, Key: KafkaBrokersKey, Value: utils.MarshalOrPanic(&ab.KafkaBrokers{Brokers: endList}), } m := NewManagerImpl() m.BeginConfig() err := m.ProposeConfig(validMessage) if err != nil { t.Fatalf("Error applying valid config: %s", err) } err = m.ProposeConfig(invalidMessage) if err == nil { t.Fatalf("Should have failed on invalid message") } err = m.ProposeConfig(zeroBrokers) if err == nil { t.Fatalf("Should have rejected empty brokers list") } for i := range badMessages { err = m.ProposeConfig(badMessages[i]) if err == nil { t.Fatalf("Should have rejected broker address which is obviously malformed") } } m.CommitConfig() nowList := m.KafkaBrokers() switch { case len(nowList) != len(endList), nowList[0] != endList[0]: t.Fatalf("Got brokers list %s when expecting brokers list %s", nowList, endList) default: return } }