Skip to content

Commit

Permalink
Restructure static bootstrapper's genesis block
Browse files Browse the repository at this point in the history
The data section of the genesis block currently output by the static
bootstrap helper consists of a single marshaled ConfigurationEnvelope.
This is not right. It should instead be a single marshaled Envelope.

This changeset also addresses the following issues:
- The previous hash of the genesis block was erroneously set to a non-nil
value.
- The signature of the makeSignedConfigurationItem() has been modified so
that the order of the input arguments makes sense.

Change-Id: I29cd095d5510dc16dccb808dc9dc8bce931cf391
Signed-off-by: Kostas Christidis <kostas@christidis.io>
  • Loading branch information
kchristidis committed Nov 12, 2016
1 parent 7e7e23c commit 82e72f4
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 44 deletions.
100 changes: 70 additions & 30 deletions orderer/common/bootstrap/static/static.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,34 @@ limitations under the License.
package static

import (
"math/rand"
"fmt"
"time"

"github.com/hyperledger/fabric/core/crypto/primitives"
"github.com/hyperledger/fabric/orderer/common/bootstrap"
"github.com/hyperledger/fabric/orderer/common/cauthdsl"
"github.com/hyperledger/fabric/orderer/common/configtx"
cb "github.com/hyperledger/fabric/protos/common"

"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes/timestamp"
)

type bootstrapper struct {
chainID []byte
}

// New returns a new static bootstrap helper
// New returns a new static bootstrap helper.
func New() bootstrap.Helper {
b := make([]byte, 16)
rand.Read(b)

return &bootstrapper{
chainID: b,
chainID, err := primitives.GetRandomBytes(16)
if err != nil {
panic(fmt.Errorf("Cannot generate random chain ID: %s", err))
}
return &bootstrapper{chainID}
}

// errorlessMarshal prevents poluting this code with many panics, if the genesis block cannot be created, the system cannot start so panic is correct
// errorlessMarshal prevents poluting this code with panics
// If the genesis block cannot be created, the system cannot start so panic is correct
func errorlessMarshal(thing proto.Message) []byte {
data, err := proto.Marshal(thing)
if err != nil {
Expand All @@ -50,19 +53,63 @@ func errorlessMarshal(thing proto.Message) []byte {
return data
}

func (b *bootstrapper) makeSignedConfigurationItem(id string, ctype cb.ConfigurationItem_ConfigurationType, data []byte, modificationPolicyID string) *cb.SignedConfigurationItem {
configurationBytes := errorlessMarshal(&cb.ConfigurationItem{
Header: &cb.ChainHeader{
ChainID: b.chainID,
func makeChainHeader(headerType cb.HeaderType, version int32, chainID []byte) *cb.ChainHeader {
return &cb.ChainHeader{
Type: int32(headerType),
Version: version,
Timestamp: &timestamp.Timestamp{
Seconds: time.Now().Unix(),
Nanos: 0,
},
ChainID: chainID,
}
}

func makeSignatureHeader(serializedCreatorCertChain []byte, nonce []byte, epoch uint64) *cb.SignatureHeader {
return &cb.SignatureHeader{
Creator: serializedCreatorCertChain,
Nonce: nonce,
Epoch: epoch,
}
}

func (b *bootstrapper) makeSignedConfigurationItem(configurationItemType cb.ConfigurationItem_ConfigurationType, modificationPolicyID string, key string, value []byte) *cb.SignedConfigurationItem {
marshaledConfigurationItem := errorlessMarshal(&cb.ConfigurationItem{
Header: makeChainHeader(cb.HeaderType_CONFIGURATION_ITEM, 1, b.chainID),
Type: configurationItemType,
LastModified: 0,
Type: ctype,
ModificationPolicy: modificationPolicyID,
Key: id,
Value: data,
Key: key,
Value: value,
})

return &cb.SignedConfigurationItem{
ConfigurationItem: configurationBytes,
ConfigurationItem: marshaledConfigurationItem,
Signatures: nil,
}
}

func (b *bootstrapper) makeConfigurationEnvelope(items ...*cb.SignedConfigurationItem) *cb.ConfigurationEnvelope {
return &cb.ConfigurationEnvelope{
Items: items,
}
}

func (b *bootstrapper) makeEnvelope(configurationEnvelope *cb.ConfigurationEnvelope) *cb.Envelope {
nonce, err := primitives.GetRandomNonce()
if err != nil {
panic(fmt.Errorf("Cannot generate random nonce: %s", err))
}
marshaledPayload := errorlessMarshal(&cb.Payload{
Header: &cb.Header{
ChainHeader: makeChainHeader(cb.HeaderType_CONFIGURATION_TRANSACTION, 1, b.chainID),
SignatureHeader: makeSignatureHeader(nil, nonce, 0),
},
Data: errorlessMarshal(configurationEnvelope),
})
return &cb.Envelope{
Payload: marshaledPayload,
Signature: nil,
}
}

Expand All @@ -77,27 +124,20 @@ func sigPolicyToPolicy(sigPolicy *cb.SignaturePolicyEnvelope) []byte {

// GenesisBlock returns the genesis block to be used for bootstrapping
func (b *bootstrapper) GenesisBlock() (*cb.Block, error) {

// Lock down the default modification policy to prevent any further policy modifications
lockdownDefaultModificationPolicy := b.makeSignedConfigurationItem(configtx.DefaultModificationPolicyID, cb.ConfigurationItem_Policy, sigPolicyToPolicy(cauthdsl.RejectAllPolicy), configtx.DefaultModificationPolicyID)

initialConfigTX := errorlessMarshal(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{
lockdownDefaultModificationPolicy,
},
})
lockdownDefaultModificationPolicy := b.makeSignedConfigurationItem(cb.ConfigurationItem_Policy, configtx.DefaultModificationPolicyID, configtx.DefaultModificationPolicyID, sigPolicyToPolicy(cauthdsl.RejectAllPolicy))

data := &cb.BlockData{
Data: [][]byte{initialConfigTX},
blockData := &cb.BlockData{
Data: [][]byte{errorlessMarshal(b.makeEnvelope(b.makeConfigurationEnvelope(lockdownDefaultModificationPolicy)))},
}

return &cb.Block{
Header: &cb.BlockHeader{
Number: 0,
PreviousHash: []byte("GENESIS"),
DataHash: data.Hash(),
PreviousHash: nil,
DataHash: blockData.Hash(),
},
Data: data,
Data: blockData,
Metadata: nil,
}, nil

}
25 changes: 16 additions & 9 deletions orderer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,27 +87,34 @@ func init() {
func retrieveConfiguration(rl rawledger.Reader) *cb.ConfigurationEnvelope {
var lastConfigTx *cb.ConfigurationEnvelope

envelope := new(cb.Envelope)
payload := new(cb.Payload)
configurationEnvelope := new(cb.ConfigurationEnvelope)

it, _ := rl.Iterator(ab.SeekInfo_OLDEST, 0)
// Iterate over the blockchain, looking for config transactions, track the most recent one encountered
// this will be the transaction which is returned
// This will be the transaction which is returned
for {
select {
case <-it.ReadyChan():
block, status := it.Next()
if status != cb.Status_SUCCESS {
panic(fmt.Errorf("Error parsing blockchain at startup: %v", status))
}
// ConfigTxs should always be by themselves
if len(block.Data.Data) != 1 {
continue
}

maybeConfigTx := &cb.ConfigurationEnvelope{}

err := proto.Unmarshal(block.Data.Data[0], maybeConfigTx)

if err == nil {
lastConfigTx = maybeConfigTx
if err := proto.Unmarshal(block.Data.Data[0], envelope); err != nil {
panic(fmt.Errorf("Block doesn't carry a message envelope: %s", err))
}
if err := proto.Unmarshal(envelope.Payload, payload); err != nil {
panic(fmt.Errorf("Message envelope doesn't carry a payload: %s", err))
}
if payload.Header.ChainHeader.Type != int32(cb.HeaderType_CONFIGURATION_TRANSACTION) {
continue
}
if err := proto.Unmarshal(payload.Data, configurationEnvelope); err == nil {
lastConfigTx = configurationEnvelope
}
default:
return lastConfigTx
Expand Down
10 changes: 5 additions & 5 deletions protos/common/configuration.proto
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,22 @@ package common;
// b) The ConfigurationSignature signature is over the concatenation of signatureHeader and the ConfigurationItem bytes (which includes a ChainHeader)
// 5. Submit new Configuration for ordering in Envelope signed by submitter
// a) The Envelope Payload has data set to the marshaled ConfigurationEnvelope
// b) The Envelope Payload has a header of type Header.Type.CONFIGURATION_TRANSACTION
//
// b) The Envelope Payload has a header of type Header.Type.CONFIGURATION_TRANSACTION
//
// The configuration manager will verify:
// 1. All configuration items and the envelope refer to the correct chain
// 2. Some configuration item has been added or modified
// 3. No existing configuration item has been ommitted
// 4. All configuration changes have a LastModification of one more than the last configuration's highest LastModification number
// 5. All configuration changes satisfy the corresponding modification policy
// 5. All configuration changes satisfy the corresponding modification policy
message ConfigurationEnvelope {
repeated SignedConfigurationItem Items = 1;
}

// This message may change slightly depending on the finalization of signature schemes for transactions
message SignedConfigurationItem {
bytes ConfigurationItem = 1;
repeated ConfigurationSignature Signatures = 2; // Signatures over the hash of Configuration
repeated ConfigurationSignature Signatures = 2; // Signatures over the hash of ConfigurationItem
}

message ConfigurationItem {
Expand Down Expand Up @@ -100,7 +100,7 @@ message SignaturePolicy {
repeated SignaturePolicy Policies = 2;
}
oneof Type {
int32 SignedBy = 1;
int32 SignedBy = 1;
NOutOf From = 2;
}
}

0 comments on commit 82e72f4

Please sign in to comment.