/* Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package blockledger import ( "github.com/golang/protobuf/proto" cb "github.com/hyperledger/fabric-protos-go/common" ab "github.com/hyperledger/fabric-protos-go/orderer" "github.com/hyperledger/fabric/common/flogging" "github.com/hyperledger/fabric/protoutil" ) var logger = flogging.MustGetLogger("common.ledger.blockledger.util") var closedChan chan struct{} func init() { closedChan = make(chan struct{}) close(closedChan) } // NotFoundErrorIterator simply always returns an error of cb.Status_NOT_FOUND, // and is generally useful for implementations of the Reader interface type NotFoundErrorIterator struct{} // Next returns nil, cb.Status_NOT_FOUND func (nfei *NotFoundErrorIterator) Next() (*cb.Block, cb.Status) { return nil, cb.Status_NOT_FOUND } // ReadyChan returns a closed channel func (nfei *NotFoundErrorIterator) ReadyChan() <-chan struct{} { return closedChan } // Close does nothing func (nfei *NotFoundErrorIterator) Close() {} // CreateNextBlock provides a utility way to construct the next block from // contents and metadata for a given ledger // XXX This will need to be modified to accept marshaled envelopes // // to accommodate non-deterministic marshaling func CreateNextBlock(rl Reader, messages []*cb.Envelope) *cb.Block { var nextBlockNumber uint64 var previousBlockHash []byte var err error if rl.Height() > 0 { it, _ := rl.Iterator(&ab.SeekPosition{ Type: &ab.SeekPosition_Newest{ Newest: &ab.SeekNewest{}, }, }) block, status := it.Next() if status != cb.Status_SUCCESS { panic("Error seeking to newest block for chain with non-zero height") } nextBlockNumber = block.Header.Number + 1 previousBlockHash = protoutil.BlockHeaderHash(block.Header) } data := &cb.BlockData{ Data: make([][]byte, len(messages)), } for i, msg := range messages { data.Data[i], err = proto.Marshal(msg) if err != nil { panic(err) } } block := protoutil.NewBlock(nextBlockNumber, previousBlockHash) block.Header.DataHash = protoutil.BlockDataHash(data) block.Data = data return block } // GetBlock is a utility method for retrieving a single block func GetBlock(rl Reader, index uint64) *cb.Block { iterator, _ := rl.Iterator(&ab.SeekPosition{ Type: &ab.SeekPosition_Specified{ Specified: &ab.SeekSpecified{Number: index}, }, }) if iterator == nil { return nil } defer iterator.Close() block, status := iterator.Next() if status != cb.Status_SUCCESS { return nil } return block } func GetBlockByNumber(rl Reader, blockNum uint64) (*cb.Block, error) { logger.Debugw("Retrieving block", "blockNum", blockNum) return rl.RetrieveBlockByNumber(blockNum) }