代码拉取完成,页面将自动刷新
/*
Copyright IBM Corp. 2017 All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package multichannel
import (
"sync"
"github.com/golang/protobuf/proto"
newchannelconfig "github.com/hyperledger/fabric/common/channelconfig"
"github.com/hyperledger/fabric/common/configtx"
"github.com/hyperledger/fabric/common/ledger/blockledger"
"github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/internal/pkg/identity"
cb "github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protoutil"
)
type blockWriterSupport interface {
identity.SignerSerializer
blockledger.ReadWriter
configtx.Validator
Update(*newchannelconfig.Bundle)
CreateBundle(channelID string, config *cb.Config) (*newchannelconfig.Bundle, error)
}
// BlockWriter efficiently writes the blockchain to disk.
// To safely use BlockWriter, only one thread should interact with it.
// BlockWriter will spawn additional committing go routines and handle locking
// so that these other go routines safely interact with the calling one.
type BlockWriter struct {
support blockWriterSupport
registrar *Registrar
lastConfigBlockNum uint64
lastConfigSeq uint64
lastBlock *cb.Block
committingBlock sync.Mutex
}
func newBlockWriter(lastBlock *cb.Block, r *Registrar, support blockWriterSupport) *BlockWriter {
bw := &BlockWriter{
support: support,
lastConfigSeq: support.Sequence(),
lastBlock: lastBlock,
registrar: r,
}
// If this is the genesis block, the lastconfig field may be empty, and, the last config block is necessarily block 0
// so no need to initialize lastConfig
if lastBlock.Header.Number != 0 {
var err error
bw.lastConfigBlockNum, err = protoutil.GetLastConfigIndexFromBlock(lastBlock)
if err != nil {
logger.Panicf("[channel: %s] Error extracting last config block from block metadata: %s", support.ChainID(), err)
}
}
logger.Debugf("[channel: %s] Creating block writer for tip of chain (blockNumber=%d, lastConfigBlockNum=%d, lastConfigSeq=%d)", support.ChainID(), lastBlock.Header.Number, bw.lastConfigBlockNum, bw.lastConfigSeq)
return bw
}
// CreateNextBlock creates a new block with the next block number, and the given contents.
func (bw *BlockWriter) CreateNextBlock(messages []*cb.Envelope) *cb.Block {
previousBlockHash := protoutil.BlockHeaderHash(bw.lastBlock.Header)
data := &cb.BlockData{
Data: make([][]byte, len(messages)),
}
var err error
for i, msg := range messages {
data.Data[i], err = proto.Marshal(msg)
if err != nil {
logger.Panicf("Could not marshal envelope: %s", err)
}
}
block := protoutil.NewBlock(bw.lastBlock.Header.Number+1, previousBlockHash)
block.Header.DataHash = protoutil.BlockDataHash(data)
block.Data = data
return block
}
// WriteConfigBlock should be invoked for blocks which contain a config transaction.
// This call will block until the new config has taken effect, then will return
// while the block is written asynchronously to disk.
func (bw *BlockWriter) WriteConfigBlock(block *cb.Block, encodedMetadataValue []byte) {
ctx, err := protoutil.ExtractEnvelope(block, 0)
if err != nil {
logger.Panicf("Told to write a config block, but could not get configtx: %s", err)
}
payload, err := protoutil.UnmarshalPayload(ctx.Payload)
if err != nil {
logger.Panicf("Told to write a config block, but configtx payload is invalid: %s", err)
}
if payload.Header == nil {
logger.Panicf("Told to write a config block, but configtx payload header is missing")
}
chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
logger.Panicf("Told to write a config block with an invalid channel header: %s", err)
}
switch chdr.Type {
case int32(cb.HeaderType_ORDERER_TRANSACTION):
newChannelConfig, err := protoutil.UnmarshalEnvelope(payload.Data)
if err != nil {
logger.Panicf("Told to write a config block with new channel, but did not have config update embedded: %s", err)
}
bw.registrar.newChain(newChannelConfig)
case int32(cb.HeaderType_CONFIG):
configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
if err != nil {
logger.Panicf("Told to write a config block with new channel, but did not have config envelope encoded: %s", err)
}
err = bw.support.Validate(configEnvelope)
if err != nil {
logger.Panicf("Told to write a config block with new config, but could not apply it: %s", err)
}
bundle, err := bw.support.CreateBundle(chdr.ChannelId, configEnvelope.Config)
if err != nil {
logger.Panicf("Told to write a config block with a new config, but could not convert it to a bundle: %s", err)
}
// Avoid Bundle update before the go-routine in WriteBlock() finished writing the previous block.
// We do this (in particular) to prevent bw.support.Sequence() from advancing before the go-routine reads it.
// In general, this prevents the StableBundle from changing before the go-routine in WriteBlock() finishes.
bw.committingBlock.Lock()
bw.committingBlock.Unlock()
bw.support.Update(bundle)
default:
logger.Panicf("Told to write a config block with unknown header type: %v", chdr.Type)
}
bw.WriteBlock(block, encodedMetadataValue)
}
// WriteBlock should be invoked for blocks which contain normal transactions.
// It sets the target block as the pending next block, and returns before it is committed.
// Before returning, it acquires the committing lock, and spawns a go routine which will
// annotate the block with metadata and signatures, and write the block to the ledger
// then release the lock. This allows the calling thread to begin assembling the next block
// before the commit phase is complete.
func (bw *BlockWriter) WriteBlock(block *cb.Block, encodedMetadataValue []byte) {
bw.committingBlock.Lock()
bw.lastBlock = block
go func() {
defer bw.committingBlock.Unlock()
bw.commitBlock(encodedMetadataValue)
}()
}
// commitBlock should only ever be invoked with the bw.committingBlock held
// this ensures that the encoded config sequence numbers stay in sync
func (bw *BlockWriter) commitBlock(encodedMetadataValue []byte) {
// Set the orderer-related metadata field
if encodedMetadataValue != nil {
bw.lastBlock.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER] = protoutil.MarshalOrPanic(&cb.Metadata{Value: encodedMetadataValue})
}
bw.addLastConfigSignature(bw.lastBlock)
bw.addBlockSignature(bw.lastBlock)
err := bw.support.Append(bw.lastBlock)
if err != nil {
logger.Panicf("[channel: %s] Could not append block: %s", bw.support.ChainID(), err)
}
logger.Debugf("[channel: %s] Wrote block [%d]", bw.support.ChainID(), bw.lastBlock.GetHeader().Number)
}
func (bw *BlockWriter) addBlockSignature(block *cb.Block) {
blockSignature := &cb.MetadataSignature{
SignatureHeader: protoutil.MarshalOrPanic(protoutil.NewSignatureHeaderOrPanic(bw.support)),
}
blockSignatureValue := protoutil.MarshalOrPanic(&cb.OrdererBlockMetadata{
LastConfig: &cb.LastConfig{Index: bw.lastConfigBlockNum},
ConsenterMetadata: bw.lastBlock.Metadata.Metadata[cb.BlockMetadataIndex_ORDERER],
})
blockSignature.Signature = protoutil.SignOrPanic(
bw.support,
util.ConcatenateBytes(blockSignatureValue, blockSignature.SignatureHeader, protoutil.BlockHeaderBytes(block.Header)),
)
block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&cb.Metadata{
Value: blockSignatureValue,
Signatures: []*cb.MetadataSignature{
blockSignature,
},
})
}
func (bw *BlockWriter) addLastConfigSignature(block *cb.Block) {
configSeq := bw.support.Sequence()
if configSeq > bw.lastConfigSeq {
logger.Debugf("[channel: %s] Detected lastConfigSeq transitioning from %d to %d, setting lastConfigBlockNum from %d to %d", bw.support.ChainID(), bw.lastConfigSeq, configSeq, bw.lastConfigBlockNum, block.Header.Number)
bw.lastConfigBlockNum = block.Header.Number
bw.lastConfigSeq = configSeq
}
lastConfigValue := protoutil.MarshalOrPanic(&cb.LastConfig{Index: bw.lastConfigBlockNum})
logger.Debugf("[channel: %s] About to write block, setting its LAST_CONFIG to %d", bw.support.ChainID(), bw.lastConfigBlockNum)
block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = protoutil.MarshalOrPanic(&cb.Metadata{
Value: lastConfigValue,
})
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。