126 lines
3.8 KiB
Go
126 lines
3.8 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package fileledger
|
|
|
|
import (
|
|
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/common/ledger"
|
|
"github.com/hyperledger/fabric/common/ledger/blockledger"
|
|
)
|
|
|
|
var logger = flogging.MustGetLogger("common.ledger.blockledger.file")
|
|
|
|
// FileLedger is a struct used to interact with a node's ledger
|
|
type FileLedger struct {
|
|
blockStore FileLedgerBlockStore
|
|
signal chan struct{}
|
|
}
|
|
|
|
// FileLedgerBlockStore defines the interface to interact with deliver when using a
|
|
// file ledger
|
|
type FileLedgerBlockStore interface {
|
|
AddBlock(block *cb.Block) error
|
|
GetBlockchainInfo() (*cb.BlockchainInfo, error)
|
|
RetrieveBlocks(startBlockNumber uint64) (ledger.ResultsIterator, error)
|
|
Shutdown()
|
|
RetrieveBlockByNumber(blockNum uint64) (*cb.Block, error)
|
|
}
|
|
|
|
// NewFileLedger creates a new FileLedger for interaction with the ledger
|
|
func NewFileLedger(blockStore FileLedgerBlockStore) *FileLedger {
|
|
return &FileLedger{blockStore: blockStore, signal: make(chan struct{})}
|
|
}
|
|
|
|
type fileLedgerIterator struct {
|
|
ledger *FileLedger
|
|
blockNumber uint64
|
|
commonIterator ledger.ResultsIterator
|
|
}
|
|
|
|
// Next blocks until there is a new block available, or until Close is called.
|
|
// It returns an error if the next block is no longer retrievable.
|
|
func (i *fileLedgerIterator) Next() (*cb.Block, cb.Status) {
|
|
result, err := i.commonIterator.Next()
|
|
if err != nil {
|
|
logger.Error(err)
|
|
return nil, cb.Status_SERVICE_UNAVAILABLE
|
|
}
|
|
// Cover the case where another thread calls Close on the iterator.
|
|
if result == nil {
|
|
return nil, cb.Status_SERVICE_UNAVAILABLE
|
|
}
|
|
return result.(*cb.Block), cb.Status_SUCCESS
|
|
}
|
|
|
|
// Close releases resources acquired by the Iterator
|
|
func (i *fileLedgerIterator) Close() {
|
|
i.commonIterator.Close()
|
|
}
|
|
|
|
// Iterator returns an Iterator, as specified by an ab.SeekInfo message, and its
|
|
// starting block number
|
|
func (fl *FileLedger) Iterator(startPosition *ab.SeekPosition) (blockledger.Iterator, uint64) {
|
|
var startingBlockNumber uint64
|
|
switch start := startPosition.Type.(type) {
|
|
case *ab.SeekPosition_Oldest:
|
|
startingBlockNumber = 0
|
|
case *ab.SeekPosition_Newest:
|
|
info, err := fl.blockStore.GetBlockchainInfo()
|
|
if err != nil {
|
|
logger.Panic(err)
|
|
}
|
|
newestBlockNumber := info.Height - 1
|
|
if info.BootstrappingSnapshotInfo != nil && newestBlockNumber == info.BootstrappingSnapshotInfo.LastBlockInSnapshot {
|
|
newestBlockNumber = info.Height
|
|
}
|
|
startingBlockNumber = newestBlockNumber
|
|
case *ab.SeekPosition_Specified:
|
|
startingBlockNumber = start.Specified.Number
|
|
height := fl.Height()
|
|
if startingBlockNumber > height {
|
|
return &blockledger.NotFoundErrorIterator{}, 0
|
|
}
|
|
case *ab.SeekPosition_NextCommit:
|
|
startingBlockNumber = fl.Height()
|
|
default:
|
|
return &blockledger.NotFoundErrorIterator{}, 0
|
|
}
|
|
|
|
iterator, err := fl.blockStore.RetrieveBlocks(startingBlockNumber)
|
|
if err != nil {
|
|
logger.Warnw("Failed to initialize block iterator", "blockNum", startingBlockNumber, "error", err)
|
|
return &blockledger.NotFoundErrorIterator{}, 0
|
|
}
|
|
|
|
return &fileLedgerIterator{ledger: fl, blockNumber: startingBlockNumber, commonIterator: iterator}, startingBlockNumber
|
|
}
|
|
|
|
// Height returns the number of blocks on the ledger
|
|
func (fl *FileLedger) Height() uint64 {
|
|
info, err := fl.blockStore.GetBlockchainInfo()
|
|
if err != nil {
|
|
logger.Panic(err)
|
|
}
|
|
return info.Height
|
|
}
|
|
|
|
// Append a new block to the ledger
|
|
func (fl *FileLedger) Append(block *cb.Block) error {
|
|
err := fl.blockStore.AddBlock(block)
|
|
if err == nil {
|
|
close(fl.signal)
|
|
fl.signal = make(chan struct{})
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (fl *FileLedger) RetrieveBlockByNumber(blockNumber uint64) (*cb.Block, error) {
|
|
return fl.blockStore.RetrieveBlockByNumber(blockNumber)
|
|
}
|