Skip to content

Commit 65e0675

Browse files
author
Jason Yellick
committed
[FAB-1528] Add block signature
https://jira.hyperledger.org/browse/FAB-1528 This changeset adds a signing interface which the MSP team has agreed to implement. It also adds a single signature for the block creation (which will be adequate for Solo/Kafka but will need to be augmented for SBFT). It also adds the signature to the last configuration item. Change-Id: I87f37b3e4ff523f7a32ccdf2e87a80cc9ca7f87a Signed-off-by: Jason Yellick <[email protected]>
1 parent 141ab4c commit 65e0675

File tree

6 files changed

+145
-14
lines changed

6 files changed

+145
-14
lines changed

orderer/mocks/multichain/multichain.go

+10
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,13 @@ func (mcs *ConsenterSupport) WriteBlock(block *cb.Block, _committers []filter.Co
8383
func (mcs *ConsenterSupport) ChainID() string {
8484
return mcs.ChainIDVal
8585
}
86+
87+
// Sign returns the bytes passed in
88+
func (mcs *ConsenterSupport) Sign(message []byte) []byte {
89+
return message
90+
}
91+
92+
// NewSignatureHeader returns an empty signature header
93+
func (mcs *ConsenterSupport) NewSignatureHeader() *cb.SignatureHeader {
94+
return &cb.SignatureHeader{}
95+
}

orderer/multichain/chainsupport.go

+66-5
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ type Chain interface {
5858

5959
// ConsenterSupport provides the resources available to a Consenter implementation
6060
type ConsenterSupport interface {
61+
Signer
6162
BlockCutter() blockcutter.Receiver
6263
SharedConfig() sharedconfig.Manager
6364
CreateNextBlock(messages []*cb.Envelope) *cb.Block
@@ -83,6 +84,7 @@ type chainSupport struct {
8384
sharedConfigManager sharedconfig.Manager
8485
ledger rawledger.ReadWriter
8586
filters *filter.RuleSet
87+
signer Signer
8688
lastConfiguration uint64
8789
lastConfigSeq uint64
8890
}
@@ -94,6 +96,7 @@ func newChainSupport(
9496
backing rawledger.ReadWriter,
9597
sharedConfigManager sharedconfig.Manager,
9698
consenters map[string]Consenter,
99+
signer Signer,
97100
) *chainSupport {
98101

99102
cutter := blockcutter.NewReceiverImpl(sharedConfigManager, filters)
@@ -110,6 +113,7 @@ func newChainSupport(
110113
cutter: cutter,
111114
filters: filters,
112115
ledger: backing,
116+
signer: signer,
113117
}
114118

115119
var err error
@@ -145,6 +149,14 @@ func (cs *chainSupport) start() {
145149
cs.chain.Start()
146150
}
147151

152+
func (cs *chainSupport) NewSignatureHeader() *cb.SignatureHeader {
153+
return cs.signer.NewSignatureHeader()
154+
}
155+
156+
func (cs *chainSupport) Sign(message []byte) []byte {
157+
return cs.signer.Sign(message)
158+
}
159+
148160
func (cs *chainSupport) SharedConfig() sharedconfig.Manager {
149161
return cs.sharedConfigManager
150162
}
@@ -181,21 +193,70 @@ func (cs *chainSupport) CreateNextBlock(messages []*cb.Envelope) *cb.Block {
181193
return rawledger.CreateNextBlock(cs.ledger, messages)
182194
}
183195

184-
func (cs *chainSupport) WriteBlock(block *cb.Block, committers []filter.Committer) *cb.Block {
185-
for _, committer := range committers {
186-
committer.Commit()
196+
// TODO, factor this out into common util code
197+
func metadataSignatureBytes(value []byte, sigHeader []byte, blockHeader []byte) []byte {
198+
result := make([]byte, len(value)+len(sigHeader)+len(blockHeader))
199+
last := 0
200+
for _, slice := range [][]byte{value, sigHeader, blockHeader} {
201+
for i := range slice {
202+
result[i+last] = slice[i]
203+
}
204+
last += len(slice)
187205
}
206+
return result
207+
}
208+
209+
func (cs *chainSupport) addBlockSignature(block *cb.Block) {
210+
logger.Debugf("%+v", cs)
211+
logger.Debugf("%+v", cs.signer)
212+
blockSignature := &cb.MetadataSignature{
213+
SignatureHeader: utils.MarshalOrPanic(cs.signer.NewSignatureHeader()),
214+
}
215+
216+
// Note, this value is intentionally nil, as this metadata is only about the signature, there is no additional metadata
217+
// information required beyond the fact that the metadata item is signed.
218+
blockSignatureValue := []byte(nil)
219+
220+
blockSignature.Signature = cs.signer.Sign(metadataSignatureBytes(blockSignatureValue, blockSignature.SignatureHeader, block.Header.Bytes()))
221+
222+
block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = utils.MarshalOrPanic(&cb.Metadata{
223+
Value: blockSignatureValue,
224+
Signatures: []*cb.MetadataSignature{
225+
blockSignature,
226+
},
227+
})
228+
}
188229

230+
func (cs *chainSupport) addLastConfigSignature(block *cb.Block) {
189231
configSeq := cs.configManager.Sequence()
190232
if configSeq > cs.lastConfigSeq {
191233
cs.lastConfiguration = block.Header.Number
192234
cs.lastConfigSeq = configSeq
193235
}
194236

237+
lastConfigSignature := &cb.MetadataSignature{
238+
SignatureHeader: utils.MarshalOrPanic(cs.signer.NewSignatureHeader()),
239+
}
240+
241+
lastConfigValue := utils.MarshalOrPanic(&cb.LastConfiguration{Index: cs.lastConfiguration})
242+
243+
lastConfigSignature.Signature = cs.signer.Sign(metadataSignatureBytes(lastConfigValue, lastConfigSignature.SignatureHeader, block.Header.Bytes()))
244+
195245
block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIGURATION] = utils.MarshalOrPanic(&cb.Metadata{
196-
Value: utils.MarshalOrPanic(&cb.LastConfiguration{Index: cs.lastConfiguration}),
197-
// XXX Add signature once signing is available
246+
Value: lastConfigValue,
247+
Signatures: []*cb.MetadataSignature{
248+
lastConfigSignature,
249+
},
198250
})
251+
}
252+
253+
func (cs *chainSupport) WriteBlock(block *cb.Block, committers []filter.Committer) *cb.Block {
254+
for _, committer := range committers {
255+
committer.Commit()
256+
}
257+
258+
cs.addBlockSignature(block)
259+
cs.addLastConfigSignature(block)
199260

200261
err := cs.ledger.Append(block)
201262
if err != nil {

orderer/multichain/chainsupport_test.go

+33-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package multichain
1818

1919
import (
20+
"bytes"
2021
"reflect"
2122
"testing"
2223

@@ -64,7 +65,7 @@ func (mc *mockCommitter) Commit() {
6465
func TestCommitConfig(t *testing.T) {
6566
ml := &mockLedgerReadWriter{}
6667
cm := &mockconfigtx.Manager{}
67-
cs := &chainSupport{ledger: ml, configManager: cm}
68+
cs := &chainSupport{ledger: ml, configManager: cm, signer: &xxxCryptoHelper{}}
6869
txs := []*cb.Envelope{makeNormalTx("foo", 0), makeNormalTx("bar", 1)}
6970
committers := []filter.Committer{&mockCommitter{}, &mockCommitter{}}
7071
block := cs.CreateNextBlock(txs)
@@ -86,10 +87,40 @@ func TestCommitConfig(t *testing.T) {
8687
}
8788
}
8889

90+
func TestMetadataSignatureBytes(t *testing.T) {
91+
value := []byte("Value")
92+
signatureHeader := []byte("SignatureHeader")
93+
blockHeader := []byte("BlockHeader")
94+
95+
sigBytes := metadataSignatureBytes(value, signatureHeader, blockHeader)
96+
expected := []byte("ValueSignatureHeaderBlockHeader")
97+
if !bytes.Equal(sigBytes, expected) {
98+
t.Errorf("Did not compute first signature bytes correctly, expected %s, got %s", expected, sigBytes)
99+
}
100+
}
101+
102+
func TestWriteBlockSignatures(t *testing.T) {
103+
ml := &mockLedgerReadWriter{}
104+
cm := &mockconfigtx.Manager{}
105+
cs := &chainSupport{ledger: ml, configManager: cm, signer: &xxxCryptoHelper{}}
106+
107+
blockMetadata := func(block *cb.Block) *cb.Metadata {
108+
metadata, err := utils.GetMetadataFromBlock(block, cb.BlockMetadataIndex_SIGNATURES)
109+
if err != nil {
110+
panic(err)
111+
}
112+
return metadata
113+
}
114+
115+
if blockMetadata(cs.WriteBlock(cb.NewBlock(0, nil), nil)) == nil {
116+
t.Fatalf("Block should have block signature")
117+
}
118+
}
119+
89120
func TestWriteLastConfiguration(t *testing.T) {
90121
ml := &mockLedgerReadWriter{}
91122
cm := &mockconfigtx.Manager{}
92-
cs := &chainSupport{ledger: ml, configManager: cm}
123+
cs := &chainSupport{ledger: ml, configManager: cm, signer: &xxxCryptoHelper{}}
93124

94125
lastConfig := func(block *cb.Block) uint64 {
95126
index, err := utils.GetLastConfigurationIndexFromBlock(block)

orderer/multichain/manager.go

+20-3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,23 @@ func (xxx xxxCryptoHelper) VerifySignature(sd *cb.SignedData) error {
4141
return nil
4242
}
4343

44+
func (xxx xxxCryptoHelper) NewSignatureHeader() *cb.SignatureHeader {
45+
return &cb.SignatureHeader{}
46+
}
47+
48+
func (xxx xxxCryptoHelper) Sign(message []byte) []byte {
49+
return message
50+
}
51+
52+
// Signer is a temporary stub interface which will be implemented by the local MSP
53+
type Signer interface {
54+
// NewSignatureHeader creates a SignatureHeader with the correct signing identity and a valid nonce
55+
NewSignatureHeader() *cb.SignatureHeader
56+
57+
// Sign a message which should embed a signature header created by NewSignatureHeader
58+
Sign(message []byte) []byte
59+
}
60+
4461
// Manager coordinates the creation and access of chains
4562
type Manager interface {
4663
// GetChain retrieves the chain support for a chain (and whether it exists)
@@ -99,14 +116,14 @@ func NewManagerImpl(ledgerFactory rawledger.Factory, consenters map[string]Conse
99116
logger.Fatalf("There appear to be two system chains %s and %s", ml.sysChain.support.ChainID(), chainID)
100117
}
101118
logger.Debugf("Starting with system chain: %s", chainID)
102-
chain := newChainSupport(createSystemChainFilters(ml, configManager), configManager, policyManager, backingLedger, sharedConfigManager, consenters)
119+
chain := newChainSupport(createSystemChainFilters(ml, configManager), configManager, policyManager, backingLedger, sharedConfigManager, consenters, &xxxCryptoHelper{})
103120
ml.chains[string(chainID)] = chain
104121
ml.sysChain = newSystemChain(chain)
105122
// We delay starting this chain, as it might try to copy and replace the chains map via newChain before the map is fully built
106123
defer chain.start()
107124
} else {
108125
logger.Debugf("Starting chain: %s", chainID)
109-
chain := newChainSupport(createStandardFilters(configManager), configManager, policyManager, backingLedger, sharedConfigManager, consenters)
126+
chain := newChainSupport(createStandardFilters(configManager), configManager, policyManager, backingLedger, sharedConfigManager, consenters, &xxxCryptoHelper{})
110127
ml.chains[string(chainID)] = chain
111128
chain.start()
112129
}
@@ -208,7 +225,7 @@ func (ml *multiLedger) newChain(configtx *cb.Envelope) {
208225
newChains[key] = value
209226
}
210227

211-
cs := newChainSupport(createStandardFilters(configManager), configManager, policyManager, backingLedger, sharedConfig, ml.consenters)
228+
cs := newChainSupport(createStandardFilters(configManager), configManager, policyManager, backingLedger, sharedConfig, ml.consenters, &xxxCryptoHelper{})
212229
chainID := configManager.ChainID()
213230

214231
logger.Debugf("Created and starting new chain %s", chainID)

protos/common/block.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@ func NewBlock(seqNum uint64, previousHash []byte) *Block {
3434
return block
3535
}
3636

37-
func (b *BlockHeader) Hash() []byte {
37+
func (b *BlockHeader) Bytes() []byte {
3838
data, err := proto.Marshal(b) // XXX this is wrong, protobuf is not the right mechanism to serialize for a hash
3939
if err != nil {
4040
panic("This should never fail and is generally irrecoverable")
4141
}
42+
return data
43+
}
4244

43-
return util.ComputeCryptoHash(data)
45+
func (b *BlockHeader) Hash() []byte {
46+
return util.ComputeCryptoHash(b.Bytes())
4447
}
4548

4649
func (b *BlockData) Hash() []byte {

protos/utils/blockutils.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,19 @@ func GetChainIDFromBlock(block *cb.Block) (string, error) {
4848
return payload.Header.ChainHeader.ChainID, nil
4949
}
5050

51+
// GetMetadataFromBlock retrieves metadata at the specified index
52+
func GetMetadataFromBlock(block *cb.Block, index cb.BlockMetadataIndex) (*cb.Metadata, error) {
53+
md := &cb.Metadata{}
54+
err := proto.Unmarshal(block.Metadata.Metadata[index], md)
55+
if err != nil {
56+
return nil, err
57+
}
58+
return md, nil
59+
}
60+
5161
// GetLastConfigurationIndexFromBlock retrieves the index of the last configuration block as encoded in the block metadata
5262
func GetLastConfigurationIndexFromBlock(block *cb.Block) (uint64, error) {
53-
md := &cb.Metadata{}
54-
err := proto.Unmarshal(block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIGURATION], md)
63+
md, err := GetMetadataFromBlock(block, cb.BlockMetadataIndex_LAST_CONFIGURATION)
5564
if err != nil {
5665
return 0, err
5766
}

0 commit comments

Comments
 (0)