e3: move txnum to erigon-lib (#847)

This commit is contained in:
Alex Sharov 2023-01-22 19:39:31 +07:00 committed by GitHub
parent 559e60f1a3
commit ed637538bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 192 additions and 3 deletions

View File

@ -28,9 +28,6 @@ func BytesToAddress(b []byte) Address {
return a
}
// BytesToAddressNoCopy - see https://tip.golang.org/ref/spec#Conversions_from_slice_to_array_pointer
func BytesToAddressNoCopy(b []byte) Address { return *(*Address)(b) }
// BigToAddress returns Address with byte values of b.
// If b is larger than len(h), b will be cropped from the left.
func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }

View File

@ -152,3 +152,9 @@ func (h *Hash) Scan(src interface{}) error {
func (h Hash) Value() (driver.Value, error) {
return h[:], nil
}
type CodeRecord struct {
BlockNumber uint64
TxNumber uint64
CodeHash Hash
}

186
common/rawdbv3/txnum.go Normal file
View File

@ -0,0 +1,186 @@
package rawdbv3
import (
"encoding/binary"
"fmt"
"sort"
"github.com/ledgerwatch/erigon-lib/kv"
)
type txNums struct{}
var TxNums txNums
// Min - returns maxTxNum in given block. If block not found - return last available value (`latest`/`pending` state)
func (txNums) Max(tx kv.Tx, blockNum uint64) (maxTxNum uint64, err error) {
var k [8]byte
binary.BigEndian.PutUint64(k[:], blockNum)
c, err := tx.Cursor(kv.MaxTxNum)
if err != nil {
return 0, err
}
defer c.Close()
_, v, err := c.SeekExact(k[:])
if err != nil {
return 0, err
}
if len(v) == 0 {
_, v, err = c.Last()
if err != nil {
return 0, err
}
if len(v) == 0 {
return 0, nil
}
}
return binary.BigEndian.Uint64(v), nil
}
// Min = `max(blockNum-1)+1` returns minTxNum in given block. If block not found - return last available value (`latest`/`pending` state)
func (txNums) Min(tx kv.Tx, blockNum uint64) (maxTxNum uint64, err error) {
if blockNum == 0 {
return 0, nil
}
var k [8]byte
binary.BigEndian.PutUint64(k[:], blockNum-1)
c, err := tx.Cursor(kv.MaxTxNum)
if err != nil {
return 0, err
}
defer c.Close()
_, v, err := c.SeekExact(k[:])
if err != nil {
return 0, err
}
if len(v) == 0 {
_, v, err = c.Last()
if err != nil {
return 0, err
}
if len(v) == 0 {
return 0, nil
}
}
return binary.BigEndian.Uint64(v) + 1, nil
}
func (txNums) Append(tx kv.RwTx, blockNum, maxTxNum uint64) (err error) {
lastK, err := LastKey(tx, kv.MaxTxNum)
if err != nil {
return err
}
if len(lastK) != 0 {
lastBlockNum := binary.BigEndian.Uint64(lastK)
if lastBlockNum > 1 && lastBlockNum+1 != blockNum { //allow genesis
return fmt.Errorf("append with gap blockNum=%d, but current heigh=%d", blockNum, lastBlockNum)
}
}
var k, v [8]byte
binary.BigEndian.PutUint64(k[:], blockNum)
binary.BigEndian.PutUint64(v[:], maxTxNum)
if err := tx.Append(kv.MaxTxNum, k[:], v[:]); err != nil {
return err
}
return nil
}
func (txNums) WriteForGenesis(tx kv.RwTx, maxTxNum uint64) (err error) {
var k, v [8]byte
binary.BigEndian.PutUint64(k[:], 0)
binary.BigEndian.PutUint64(v[:], maxTxNum)
return tx.Put(kv.MaxTxNum, k[:], v[:])
}
func (txNums) Truncate(tx kv.RwTx, blockNum uint64) (err error) {
var seek [8]byte
binary.BigEndian.PutUint64(seek[:], blockNum)
c, err := tx.RwCursor(kv.MaxTxNum)
if err != nil {
return err
}
defer c.Close()
for k, _, err := c.Seek(seek[:]); k != nil; k, _, err = c.Next() {
if err != nil {
return err
}
if err = c.DeleteCurrent(); err != nil {
return err
}
}
return nil
}
func (txNums) FindBlockNum(tx kv.Tx, endTxNumMinimax uint64) (ok bool, blockNum uint64, err error) {
var seek [8]byte
c, err := tx.Cursor(kv.MaxTxNum)
if err != nil {
return false, 0, err
}
defer c.Close()
cnt, err := c.Count()
if err != nil {
return false, 0, err
}
blockNum = uint64(sort.Search(int(cnt), func(i int) bool {
binary.BigEndian.PutUint64(seek[:], uint64(i))
var v []byte
_, v, err = c.SeekExact(seek[:])
return binary.BigEndian.Uint64(v) >= endTxNumMinimax
}))
if err != nil {
return false, 0, err
}
if blockNum == cnt {
return false, 0, nil
}
return true, blockNum, nil
}
// LastKey
func LastKey(tx kv.Tx, table string) ([]byte, error) {
c, err := tx.Cursor(table)
if err != nil {
return nil, err
}
defer c.Close()
k, _, err := c.Last()
if err != nil {
return nil, err
}
return k, nil
}
// Last - candidate on move to kv.Tx interface
func Last(tx kv.Tx, table string) ([]byte, []byte, error) {
c, err := tx.Cursor(table)
if err != nil {
return nil, nil, err
}
defer c.Close()
k, v, err := c.Last()
if err != nil {
return nil, nil, err
}
return k, v, nil
}
// SecondKey - useful if table always has zero-key (for example genesis block)
func SecondKey(tx kv.Tx, table string) ([]byte, error) {
c, err := tx.Cursor(table)
if err != nil {
return nil, err
}
defer c.Close()
_, _, err = c.First()
if err != nil {
return nil, err
}
k, _, err := c.Next()
if err != nil {
return nil, err
}
return k, nil
}