erigon-pulse/ethdb/history_index.go
b00ris bcee4845dc
Thin history (#272)
* save state

* remove repair

* save state

* remove emptydb check

* save state

* add walkAsOf test

* add WalkAsOf and MultiWalkAsOf tests

* deployed contracts counter

* reference counter for contract code

* drop storage root&contract hash for changesets

* start incarnation is 1(save state)

* fix ReorgOverSelfDestruct test

* hack fix TestReorgOverSelfDestruct

* test benchmark

* cleanup

* remove useless debug

* remove print trie

* return remove subtrie call  to updateTrieRoot

* save state

* add mutation test

* remove useless test

* fix

* added mutation commit test

* rename experiment to thin history

* thin history mutation commit test

* fix ethdb tests

* getAsOf test

* add test&fix history index

* fix test

* make test for index search

* compute trie root incarnation fix

* tests fixes

* done job in case of panic

* fix lint

* fix&test for bad incarnation

* fix initial incarnation for genesis

* fix lint

* fix changeset test

* fix storage ranges test

* fix lint

* move set incarnation to create contract

* add comment

Co-authored-by: ledgerwatch <akhounov@gmail.com>
Co-authored-by: Evgeny Danilenko <6655321@bk.ru>
2019-12-20 15:25:40 +03:00

130 lines
2.4 KiB
Go

package ethdb
import (
"github.com/ledgerwatch/bolt"
"github.com/ledgerwatch/turbo-geth/common/dbutils"
"github.com/ledgerwatch/turbo-geth/rlp"
"sort"
)
//
type HistoryIndex []uint64
func (hi *HistoryIndex) Encode() ([]byte, error) {
return rlp.EncodeToBytes(hi)
}
func (hi *HistoryIndex) Decode(s []byte) error {
if len(s) == 0 {
return nil
}
return rlp.DecodeBytes(s, &hi)
}
func (hi *HistoryIndex) Append(v uint64) *HistoryIndex {
*hi = append(*hi, v)
if !sort.SliceIsSorted(*hi, func(i, j int) bool {
return (*hi)[i] <= (*hi)[j]
}) {
sort.Slice(*hi, func(i, j int) bool {
return (*hi)[i] <= (*hi)[j]
})
}
return hi
}
//most common operation is remove one from the tail
func (hi *HistoryIndex) Remove(v uint64) *HistoryIndex {
for i := len(*hi) - 1; i >= 0; i-- {
if (*hi)[i] == v {
*hi = append((*hi)[:i], (*hi)[i+1:]...)
}
}
return hi
}
func (hi *HistoryIndex) Search(v uint64) (uint64, bool) {
ln := len(*hi)
if ln == 0 {
return 0, false
}
if (*hi)[ln-1] < v {
return 0, false
}
for i := ln - 1; i >= 0; i-- {
if v == (*hi)[i] {
return v, true
}
if (*hi)[i] < v {
return (*hi)[i+1], true
}
}
return (*hi)[0], true
}
func AppendToIndex(b []byte, timestamp uint64) ([]byte, error) {
v := new(HistoryIndex)
if err := v.Decode(b); err != nil {
return nil, err
}
v.Append(timestamp)
return v.Encode()
}
func RemoveFromIndex(b []byte, timestamp uint64) ([]byte, bool, error) {
v := new(HistoryIndex)
if err := v.Decode(b); err != nil {
return nil, false, err
}
v.Remove(timestamp)
res, err := v.Encode()
if len(*v) == 0 {
return res, true, err
}
return res, false, err
}
func BoltDBFindByHistory(tx *bolt.Tx, hBucket []byte, key []byte, timestamp uint64) ([]byte, error) {
//check
hB := tx.Bucket(hBucket)
if hB == nil {
return nil, ErrKeyNotFound
}
v, _ := hB.Get(key)
index := new(HistoryIndex)
err := index.Decode(v)
if err != nil {
return nil, err
}
changeSetBlock, ok := index.Search(timestamp)
if !ok {
return nil, ErrKeyNotFound
}
csB := tx.Bucket(dbutils.ChangeSetBucket)
if csB == nil {
return nil, ErrKeyNotFound
}
changeSetData, _ := csB.Get(dbutils.CompositeChangeSetKey(dbutils.EncodeTimestamp(changeSetBlock), hBucket))
cs, err := dbutils.DecodeChangeSet(changeSetData)
if err != nil {
return nil, err
}
var data []byte
data, err = cs.FindLast(key)
if err != nil {
return nil, ErrKeyNotFound
}
return data, nil
}