github.com/ledgerwatch/erigon-lib@v1.0.0/kv/rawdbv3/txnum.go (about) 1 /* 2 Copyright 2021 Erigon contributors 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 rawdbv3 18 19 import ( 20 "encoding/binary" 21 "fmt" 22 "sort" 23 24 "github.com/ledgerwatch/erigon-lib/kv" 25 ) 26 27 type txNums struct{} 28 29 var TxNums txNums 30 31 // Min - returns maxTxNum in given block. If block not found - return last available value (`latest`/`pending` state) 32 func (txNums) Max(tx kv.Tx, blockNum uint64) (maxTxNum uint64, err error) { 33 var k [8]byte 34 binary.BigEndian.PutUint64(k[:], blockNum) 35 c, err := tx.Cursor(kv.MaxTxNum) 36 if err != nil { 37 return 0, err 38 } 39 defer c.Close() 40 _, v, err := c.SeekExact(k[:]) 41 if err != nil { 42 return 0, err 43 } 44 if len(v) == 0 { 45 _, v, err = c.Last() 46 if err != nil { 47 return 0, err 48 } 49 if len(v) == 0 { 50 return 0, nil 51 } 52 } 53 return binary.BigEndian.Uint64(v), nil 54 } 55 56 // Min = `max(blockNum-1)+1` returns minTxNum in given block. If block not found - return last available value (`latest`/`pending` state) 57 func (txNums) Min(tx kv.Tx, blockNum uint64) (maxTxNum uint64, err error) { 58 if blockNum == 0 { 59 return 0, nil 60 } 61 var k [8]byte 62 binary.BigEndian.PutUint64(k[:], blockNum-1) 63 c, err := tx.Cursor(kv.MaxTxNum) 64 if err != nil { 65 return 0, err 66 } 67 defer c.Close() 68 69 _, v, err := c.SeekExact(k[:]) 70 if err != nil { 71 return 0, err 72 } 73 if len(v) == 0 { 74 _, v, err = c.Last() 75 if err != nil { 76 return 0, err 77 } 78 if len(v) == 0 { 79 return 0, nil 80 } 81 } 82 return binary.BigEndian.Uint64(v) + 1, nil 83 } 84 85 func (txNums) Append(tx kv.RwTx, blockNum, maxTxNum uint64) (err error) { 86 lastK, err := LastKey(tx, kv.MaxTxNum) 87 if err != nil { 88 return err 89 } 90 if len(lastK) != 0 { 91 lastBlockNum := binary.BigEndian.Uint64(lastK) 92 if lastBlockNum > 1 && lastBlockNum+1 != blockNum { //allow genesis 93 return fmt.Errorf("append with gap blockNum=%d, but current heigh=%d", blockNum, lastBlockNum) 94 } 95 } 96 97 var k, v [8]byte 98 binary.BigEndian.PutUint64(k[:], blockNum) 99 binary.BigEndian.PutUint64(v[:], maxTxNum) 100 if err := tx.Append(kv.MaxTxNum, k[:], v[:]); err != nil { 101 return err 102 } 103 return nil 104 } 105 func (txNums) WriteForGenesis(tx kv.RwTx, maxTxNum uint64) (err error) { 106 var k, v [8]byte 107 binary.BigEndian.PutUint64(k[:], 0) 108 binary.BigEndian.PutUint64(v[:], maxTxNum) 109 return tx.Put(kv.MaxTxNum, k[:], v[:]) 110 } 111 func (txNums) Truncate(tx kv.RwTx, blockNum uint64) (err error) { 112 var seek [8]byte 113 binary.BigEndian.PutUint64(seek[:], blockNum) 114 c, err := tx.RwCursor(kv.MaxTxNum) 115 if err != nil { 116 return err 117 } 118 defer c.Close() 119 for k, _, err := c.Seek(seek[:]); k != nil; k, _, err = c.Next() { 120 if err != nil { 121 return err 122 } 123 if err = c.DeleteCurrent(); err != nil { 124 return err 125 } 126 127 } 128 return nil 129 } 130 func (txNums) FindBlockNum(tx kv.Tx, endTxNumMinimax uint64) (ok bool, blockNum uint64, err error) { 131 var seek [8]byte 132 c, err := tx.Cursor(kv.MaxTxNum) 133 if err != nil { 134 return false, 0, err 135 } 136 defer c.Close() 137 138 cnt, err := c.Count() 139 if err != nil { 140 return false, 0, err 141 } 142 143 blockNum = uint64(sort.Search(int(cnt), func(i int) bool { 144 binary.BigEndian.PutUint64(seek[:], uint64(i)) 145 var v []byte 146 _, v, err = c.SeekExact(seek[:]) 147 return binary.BigEndian.Uint64(v) >= endTxNumMinimax 148 })) 149 if err != nil { 150 return false, 0, err 151 } 152 if blockNum == cnt { 153 return false, 0, nil 154 } 155 return true, blockNum, nil 156 } 157 func (txNums) Last(tx kv.Tx) (blockNum, txNum uint64, err error) { 158 c, err := tx.Cursor(kv.MaxTxNum) 159 if err != nil { 160 return 0, 0, err 161 } 162 defer c.Close() 163 164 lastK, lastV, err := c.Last() 165 if err != nil { 166 return 0, 0, err 167 } 168 if lastK == nil || lastV == nil { 169 return 0, 0, nil 170 } 171 return binary.BigEndian.Uint64(lastK), binary.BigEndian.Uint64(lastV), nil 172 } 173 func (txNums) First(tx kv.Tx) (blockNum, txNum uint64, err error) { 174 c, err := tx.Cursor(kv.MaxTxNum) 175 if err != nil { 176 return 0, 0, err 177 } 178 defer c.Close() 179 180 lastK, lastV, err := c.First() 181 if err != nil { 182 return 0, 0, err 183 } 184 if lastK == nil || lastV == nil { 185 return 0, 0, nil 186 } 187 return binary.BigEndian.Uint64(lastK), binary.BigEndian.Uint64(lastV), nil 188 } 189 190 // LastKey 191 func LastKey(tx kv.Tx, table string) ([]byte, error) { 192 c, err := tx.Cursor(table) 193 if err != nil { 194 return nil, err 195 } 196 defer c.Close() 197 k, _, err := c.Last() 198 if err != nil { 199 return nil, err 200 } 201 return k, nil 202 } 203 204 // Last - candidate on move to kv.Tx interface 205 func Last(tx kv.Tx, table string) ([]byte, []byte, error) { 206 c, err := tx.Cursor(table) 207 if err != nil { 208 return nil, nil, err 209 } 210 defer c.Close() 211 k, v, err := c.Last() 212 if err != nil { 213 return nil, nil, err 214 } 215 return k, v, nil 216 } 217 218 // SecondKey - useful if table always has zero-key (for example genesis block) 219 func SecondKey(tx kv.Tx, table string) ([]byte, error) { 220 c, err := tx.Cursor(table) 221 if err != nil { 222 return nil, err 223 } 224 defer c.Close() 225 _, _, err = c.First() 226 if err != nil { 227 return nil, err 228 } 229 k, _, err := c.Next() 230 if err != nil { 231 return nil, err 232 } 233 return k, nil 234 }