Skip to content

Commit

Permalink
[FAB-1523] Populate block metadata LastConfig
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-1523

This changeset adds new data types for Metadata and for
LastConfiguration which is the second field of the block metadata.

The Metadata type is intended to accomodate the other metadata fields as
well, but is currently only utilized for the LastConfiguration.

This changeset also populates the LastConfiguration field of the block
metadata with this new data structure.

Change-Id: I36e72f4c27b67dd7455aae2f423b4b14e54f9413
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Jan 10, 2017
1 parent f806802 commit 75909aa
Show file tree
Hide file tree
Showing 22 changed files with 363 additions and 131 deletions.
4 changes: 4 additions & 0 deletions common/configtx/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ func (mcm *mockConfigManager) ChainID() string {
panic("Unimplemented")
}

func (mcm *mockConfigManager) Sequence() uint64 {
panic("Unimplemented")
}

func TestForwardNonConfig(t *testing.T) {
cf := NewFilter(&mockConfigManager{})
result, _ := cf.Apply(&cb.Envelope{
Expand Down
10 changes: 9 additions & 1 deletion common/configtx/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import (
"github.com/hyperledger/fabric/common/policies"
cb "github.com/hyperledger/fabric/protos/common"

"github.com/golang/protobuf/proto"
"errors"
"github.com/golang/protobuf/proto"
)

// Handler provides a hook which allows other pieces of code to participate in config proposals
Expand Down Expand Up @@ -52,6 +52,9 @@ type Manager interface {

// ChainID retrieves the chain ID associated with this manager
ChainID() string

// Sequence returns the current sequence number of the configuration
Sequence() uint64
}

// DefaultModificationPolicyID is the ID of the policy used when no other policy can be resolved, for instance when attempting to create a new config item
Expand Down Expand Up @@ -295,3 +298,8 @@ func (cm *configurationManager) Apply(configtx *cb.ConfigurationEnvelope) error
func (cm *configurationManager) ChainID() string {
return cm.chainID
}

// Sequence returns the current sequence number of the configuration
func (cm *configurationManager) Sequence() uint64 {
return cm.sequence
}
19 changes: 8 additions & 11 deletions orderer/common/bootstrap/provisional/provisional.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,12 @@ func (cbs *commonBootstrapper) makeGenesisBlock(configEnvelope *cb.Configuration
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,
}
block := cb.NewBlock(0, nil)
block.Data = &cb.BlockData{Data: [][]byte{utils.MarshalOrPanic(envelope)}}
block.Header.DataHash = block.Data.Hash()
block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIGURATION] = utils.MarshalOrPanic(&cb.Metadata{
Value: utils.MarshalOrPanic(&cb.LastConfiguration{Index: 0}),
})

return block
}
9 changes: 7 additions & 2 deletions orderer/common/bootstrap/provisional/provisional_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"testing"

"github.com/hyperledger/fabric/orderer/localconfig"
cb "github.com/hyperledger/fabric/protos/common"
)

var confSolo, confKafka *config.TopLevel
Expand Down Expand Up @@ -50,8 +51,12 @@ func TestGenesisBlockHeader(t *testing.T) {
func TestGenesisMetadata(t *testing.T) {
for _, tc := range testCases {
genesisBlock := New(tc).GenesisBlock()
if genesisBlock.Metadata != nil {
t.Fatalf("Expected metadata nil, got %x", genesisBlock.Metadata)
if genesisBlock.Metadata == nil {
t.Fatalf("Expected non-nil metadata")
}

if genesisBlock.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIGURATION] == nil {
t.Fatalf("Should have last config set")
}
}
}
14 changes: 7 additions & 7 deletions orderer/common/deliver/deliver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func TestOldestSeek(t *testing.T) {
mm := newMockMultichainManager()
for i := 1; i < ledgerSize; i++ {
ledger := mm.chains[string(systemChainID)].ledger
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil))
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}))
}

m := newMockD()
Expand Down Expand Up @@ -159,7 +159,7 @@ func TestNewestSeek(t *testing.T) {
mm := newMockMultichainManager()
for i := 1; i < ledgerSize; i++ {
ledger := mm.chains[string(systemChainID)].ledger
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil))
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}))
}

m := newMockD()
Expand Down Expand Up @@ -191,7 +191,7 @@ func TestSpecificSeek(t *testing.T) {
mm := newMockMultichainManager()
for i := 1; i < ledgerSize; i++ {
ledger := mm.chains[string(systemChainID)].ledger
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil))
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}))
}

m := newMockD()
Expand Down Expand Up @@ -229,7 +229,7 @@ func TestBadSeek(t *testing.T) {
mm := newMockMultichainManager()
for i := 1; i < ledgerSize; i++ {
ledger := mm.chains[string(systemChainID)].ledger
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil))
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}))
}

m := newMockD()
Expand All @@ -254,7 +254,7 @@ func TestFailFastSeek(t *testing.T) {
mm := newMockMultichainManager()
for i := 1; i < ledgerSize; i++ {
ledger := mm.chains[string(systemChainID)].ledger
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil))
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}))
}

m := newMockD()
Expand Down Expand Up @@ -288,7 +288,7 @@ func TestBlockingSeek(t *testing.T) {
mm := newMockMultichainManager()
for i := 1; i < ledgerSize; i++ {
ledger := mm.chains[string(systemChainID)].ledger
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}, nil))
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", i))}}))
}

m := newMockD()
Expand All @@ -315,7 +315,7 @@ func TestBlockingSeek(t *testing.T) {
}

ledger := mm.chains[string(systemChainID)].ledger
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", ledgerSize+1))}}, nil))
ledger.Append(rawledger.CreateNextBlock(ledger, []*cb.Envelope{&cb.Envelope{Payload: []byte(fmt.Sprintf("%d", ledgerSize+1))}}))

select {
case deliverReply := <-m.sendChan:
Expand Down
3 changes: 2 additions & 1 deletion orderer/kafka/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,8 @@ func (ch *chainImpl) loop() {
}
// If !ok, batches == nil, so this will be skipped
for i, batch := range batches {
ch.support.WriteBlock(batch, nil, committers[i])
block := ch.support.CreateNextBlock(batch)
ch.support.WriteBlock(block, committers[i])
}
}
case <-ch.exitChan: // when Halt() is called
Expand Down
49 changes: 49 additions & 0 deletions orderer/mocks/configtx/configtx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
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 configtx

import cb "github.com/hyperledger/fabric/protos/common"

// Manager is a mock implementation of configtx.Manager
type Manager struct {
// ChainIDVal is returned as the result of ChainID()
ChainIDVal string

// SequenceVal is returned as the result of Sequence()
SequenceVal uint64
}

// ConsensusType returns the ConsensusTypeVal
func (cm *Manager) ChainID() string {
return cm.ChainIDVal
}

// BatchSize returns the BatchSizeVal
func (cm *Manager) Sequence() uint64 {
return cm.SequenceVal
}

// Apply panics
func (cm *Manager) Apply(configtx *cb.ConfigurationEnvelope) error {
panic("Unimplemented")
}

// Validate panics
func (cm *Manager) Validate(configtx *cb.ConfigurationEnvelope) error {
panic("Unimplemented")

}
27 changes: 27 additions & 0 deletions orderer/mocks/configtx/configtx_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
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 configtx

import (
"testing"

"github.com/hyperledger/fabric/common/configtx"
)

func TestConfigtxManagerInterface(t *testing.T) {
_ = configtx.Manager(&Manager{})
}
22 changes: 20 additions & 2 deletions orderer/mocks/multichain/multichain.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
mockblockcutter "github.com/hyperledger/fabric/orderer/mocks/blockcutter"
mocksharedconfig "github.com/hyperledger/fabric/orderer/mocks/sharedconfig"
cb "github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/utils"

"github.com/op/go-logging"
)
Expand Down Expand Up @@ -55,10 +56,27 @@ func (mcs *ConsenterSupport) SharedConfig() sharedconfig.Manager {
return mcs.SharedConfigVal
}

// CreateNextBlock creates a simple block structure with the given data
func (mcs *ConsenterSupport) CreateNextBlock(data []*cb.Envelope) *cb.Block {
block := cb.NewBlock(0, nil)
mtxs := make([][]byte, len(data))
for i := range data {
mtxs[i] = utils.MarshalOrPanic(data[i])
}
block.Data = &cb.BlockData{Data: mtxs}
return block
}

// WriteBlock writes data to the Batches channel
func (mcs *ConsenterSupport) WriteBlock(data []*cb.Envelope, metadata [][]byte, committers []filter.Committer) {
// Note that _committers is ignored by this mock implementation
func (mcs *ConsenterSupport) WriteBlock(block *cb.Block, _committers []filter.Committer) *cb.Block {
logger.Debugf("mockWriter: attempting to write batch")
mcs.Batches <- data
umtxs := make([]*cb.Envelope, len(block.Data.Data))
for i := range block.Data.Data {
umtxs[i] = utils.UnmarshalEnvelopeOrPanic(block.Data.Data[i])
}
mcs.Batches <- umtxs
return block
}

// ChainID returns the chain ID this specific consenter instance is associated with
Expand Down
29 changes: 26 additions & 3 deletions orderer/multichain/chainsupport.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/hyperledger/fabric/orderer/common/sharedconfig"
"github.com/hyperledger/fabric/orderer/rawledger"
cb "github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/utils"
)

// Consenter defines the backing ordering mechanism
Expand Down Expand Up @@ -59,7 +60,8 @@ type Chain interface {
type ConsenterSupport interface {
BlockCutter() blockcutter.Receiver
SharedConfig() sharedconfig.Manager
WriteBlock(data []*cb.Envelope, metadata [][]byte, committers []filter.Committer)
CreateNextBlock(messages []*cb.Envelope) *cb.Block
WriteBlock(block *cb.Block, committers []filter.Committer) *cb.Block
ChainID() string // ChainID returns the chain ID this specific consenter instance is associated with
}

Expand All @@ -81,6 +83,8 @@ type chainSupport struct {
sharedConfigManager sharedconfig.Manager
ledger rawledger.ReadWriter
filters *filter.RuleSet
lastConfiguration uint64
lastConfigSeq uint64
}

func newChainSupport(
Expand Down Expand Up @@ -173,10 +177,29 @@ func (cs *chainSupport) Enqueue(env *cb.Envelope) bool {
return cs.chain.Enqueue(env)
}

func (cs *chainSupport) WriteBlock(data []*cb.Envelope, metadata [][]byte, committers []filter.Committer) {
func (cs *chainSupport) CreateNextBlock(messages []*cb.Envelope) *cb.Block {
return rawledger.CreateNextBlock(cs.ledger, messages)
}

func (cs *chainSupport) WriteBlock(block *cb.Block, committers []filter.Committer) *cb.Block {
for _, committer := range committers {
committer.Commit()
}

cs.ledger.Append(rawledger.CreateNextBlock(cs.ledger, data, metadata))
configSeq := cs.configManager.Sequence()
if configSeq > cs.lastConfigSeq {
cs.lastConfiguration = block.Header.Number
cs.lastConfigSeq = configSeq
}

block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIGURATION] = utils.MarshalOrPanic(&cb.Metadata{
Value: utils.MarshalOrPanic(&cb.LastConfiguration{Index: cs.lastConfiguration}),
// XXX Add signature once signing is available
})

err := cs.ledger.Append(block)
if err != nil {
logger.Panicf("Could not append block: %s", err)
}
return block
}

0 comments on commit 75909aa

Please sign in to comment.