diff --git a/orderer/common/bootstrap/static/static.go b/orderer/common/bootstrap/static/static.go index c20e2c28f68..f4849c283ee 100644 --- a/orderer/common/bootstrap/static/static.go +++ b/orderer/common/bootstrap/static/static.go @@ -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 { @@ -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: ×tamp.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, } } @@ -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 - } diff --git a/orderer/main.go b/orderer/main.go index b9d605b1826..988604c0084 100644 --- a/orderer/main.go +++ b/orderer/main.go @@ -87,9 +87,13 @@ 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(): @@ -97,17 +101,20 @@ func retrieveConfiguration(rl rawledger.Reader) *cb.ConfigurationEnvelope { 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 diff --git a/protos/common/configuration.proto b/protos/common/configuration.proto index c226296475c..5409a8b4d60 100644 --- a/protos/common/configuration.proto +++ b/protos/common/configuration.proto @@ -35,14 +35,14 @@ 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; } @@ -50,7 +50,7 @@ message ConfigurationEnvelope { // 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 { @@ -100,7 +100,7 @@ message SignaturePolicy { repeated SignaturePolicy Policies = 2; } oneof Type { - int32 SignedBy = 1; + int32 SignedBy = 1; NOutOf From = 2; } }