github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/orderer/ledger/ram/impl.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package ramledger 18 19 import ( 20 "bytes" 21 "fmt" 22 23 "github.com/hyperledger/fabric/orderer/ledger" 24 cb "github.com/hyperledger/fabric/protos/common" 25 ab "github.com/hyperledger/fabric/protos/orderer" 26 "github.com/op/go-logging" 27 ) 28 29 var logger = logging.MustGetLogger("orderer/ramledger") 30 31 type cursor struct { 32 list *simpleList 33 } 34 35 type simpleList struct { 36 next *simpleList 37 signal chan struct{} 38 block *cb.Block 39 } 40 41 type ramLedger struct { 42 maxSize int 43 size int 44 oldest *simpleList 45 newest *simpleList 46 } 47 48 // Next blocks until there is a new block available, or returns an error if the 49 // next block is no longer retrievable 50 func (cu *cursor) Next() (*cb.Block, cb.Status) { 51 // This only loops once, as signal reading indicates non-nil next 52 for { 53 if cu.list.next != nil { 54 cu.list = cu.list.next 55 return cu.list.block, cb.Status_SUCCESS 56 } 57 <-cu.list.signal 58 } 59 } 60 61 // ReadyChan supplies a channel which will block until Next will not block 62 func (cu *cursor) ReadyChan() <-chan struct{} { 63 return cu.list.signal 64 } 65 66 // Iterator returns an Iterator, as specified by a cb.SeekInfo message, and its 67 // starting block number 68 func (rl *ramLedger) Iterator(startPosition *ab.SeekPosition) (ledger.Iterator, uint64) { 69 var list *simpleList 70 switch start := startPosition.Type.(type) { 71 case *ab.SeekPosition_Oldest: 72 oldest := rl.oldest 73 list = &simpleList{ 74 block: &cb.Block{Header: &cb.BlockHeader{Number: oldest.block.Header.Number - 1}}, 75 next: oldest, 76 signal: make(chan struct{}), 77 } 78 close(list.signal) 79 case *ab.SeekPosition_Newest: 80 newest := rl.newest 81 list = &simpleList{ 82 block: &cb.Block{Header: &cb.BlockHeader{Number: newest.block.Header.Number - 1}}, 83 next: newest, 84 signal: make(chan struct{}), 85 } 86 close(list.signal) 87 case *ab.SeekPosition_Specified: 88 oldest := rl.oldest 89 specified := start.Specified.Number 90 logger.Debugf("Attempting to return block %d", specified) 91 92 // Note the two +1's here is to accommodate the 'preGenesis' block of ^uint64(0) 93 if specified+1 < oldest.block.Header.Number+1 || specified > rl.newest.block.Header.Number+1 { 94 logger.Debugf("Returning error iterator because specified seek was %d with oldest %d and newest %d", 95 specified, rl.oldest.block.Header.Number, rl.newest.block.Header.Number) 96 return &ledger.NotFoundErrorIterator{}, 0 97 } 98 99 if specified == oldest.block.Header.Number { 100 list = &simpleList{ 101 block: &cb.Block{Header: &cb.BlockHeader{Number: oldest.block.Header.Number - 1}}, 102 next: oldest, 103 signal: make(chan struct{}), 104 } 105 close(list.signal) 106 break 107 } 108 109 list = oldest 110 for { 111 if list.block.Header.Number == specified-1 { 112 break 113 } 114 list = list.next // No need for nil check, because of range check above 115 } 116 } 117 cursor := &cursor{list: list} 118 blockNum := list.block.Header.Number + 1 119 120 // If the cursor is for pre-genesis, skip it, the block number wraps 121 if blockNum == ^uint64(0) { 122 cursor.Next() 123 blockNum++ 124 } 125 126 return cursor, blockNum 127 } 128 129 // Height returns the number of blocks on the ledger 130 func (rl *ramLedger) Height() uint64 { 131 return rl.newest.block.Header.Number + 1 132 } 133 134 // Append appends a new block to the ledger 135 func (rl *ramLedger) Append(block *cb.Block) error { 136 if block.Header.Number != rl.newest.block.Header.Number+1 { 137 return fmt.Errorf("Block number should have been %d but was %d", 138 rl.newest.block.Header.Number+1, block.Header.Number) 139 } 140 141 if rl.newest.block.Header.Number+1 != 0 { // Skip this check for genesis block insertion 142 if !bytes.Equal(block.Header.PreviousHash, rl.newest.block.Header.Hash()) { 143 return fmt.Errorf("Block should have had previous hash of %x but was %x", 144 rl.newest.block.Header.Hash(), block.Header.PreviousHash) 145 } 146 } 147 148 rl.appendBlock(block) 149 return nil 150 } 151 152 func (rl *ramLedger) appendBlock(block *cb.Block) { 153 rl.newest.next = &simpleList{ 154 signal: make(chan struct{}), 155 block: block, 156 } 157 158 lastSignal := rl.newest.signal 159 logger.Debugf("Sending signal that block %d has a successor", rl.newest.block.Header.Number) 160 rl.newest = rl.newest.next 161 close(lastSignal) 162 163 rl.size++ 164 165 if rl.size > rl.maxSize { 166 logger.Debugf("RAM ledger max size about to be exceeded, removing oldest item: %d", 167 rl.oldest.block.Header.Number) 168 rl.oldest = rl.oldest.next 169 rl.size-- 170 } 171 }