From ed637538bf95e2b60a97e427d19ca8030495351d Mon Sep 17 00:00:00 2001 From: Alex Sharov Date: Sun, 22 Jan 2023 19:39:31 +0700 Subject: [PATCH] e3: move txnum to erigon-lib (#847) --- common/address.go | 3 - common/hash.go | 6 ++ common/rawdbv3/txnum.go | 186 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 common/rawdbv3/txnum.go diff --git a/common/address.go b/common/address.go index c2c5e8d79..184db2b6f 100644 --- a/common/address.go +++ b/common/address.go @@ -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()) } diff --git a/common/hash.go b/common/hash.go index 6b6cf3fbb..94b763aba 100644 --- a/common/hash.go +++ b/common/hash.go @@ -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 +} diff --git a/common/rawdbv3/txnum.go b/common/rawdbv3/txnum.go new file mode 100644 index 000000000..c10b46f73 --- /dev/null +++ b/common/rawdbv3/txnum.go @@ -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 +}