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  }