github.com/amazechain/amc@v0.1.3/modules/state/history.go (about)

     1  // Copyright 2023 The AmazeChain Authors
     2  // This file is part of the AmazeChain library.
     3  //
     4  // The AmazeChain library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The AmazeChain library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the AmazeChain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package state
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/binary"
    22  	"errors"
    23  	"fmt"
    24  	"github.com/RoaringBitmap/roaring/roaring64"
    25  	"github.com/amazechain/amc/common/account"
    26  	"github.com/amazechain/amc/common/types"
    27  	"github.com/amazechain/amc/modules"
    28  	"github.com/amazechain/amc/modules/changeset"
    29  	"github.com/amazechain/amc/modules/ethdb"
    30  	"github.com/amazechain/amc/modules/ethdb/bitmapdb"
    31  	"github.com/ledgerwatch/erigon-lib/kv"
    32  )
    33  
    34  func GetAsOf(tx kv.Tx, indexC kv.Cursor, changesC kv.CursorDupSort, storage bool, key []byte, timestamp uint64) ([]byte, error) {
    35  	v, err := FindByHistory(tx, indexC, changesC, storage, key, timestamp)
    36  	if err == nil {
    37  		return v, nil
    38  	}
    39  	if !errors.Is(err, ethdb.ErrKeyNotFound) {
    40  		return nil, err
    41  	}
    42  	if storage {
    43  		return tx.GetOne(modules.Storage, key)
    44  	}
    45  	return tx.GetOne(modules.Account, key)
    46  }
    47  
    48  func FindByHistory(tx kv.Tx, indexC kv.Cursor, changesC kv.CursorDupSort, storage bool, key []byte, timestamp uint64) ([]byte, error) {
    49  	var csBucket string
    50  	if storage {
    51  		csBucket = modules.StorageChangeSet
    52  	} else {
    53  		csBucket = modules.AccountChangeSet
    54  	}
    55  
    56  	k, v, seekErr := indexC.Seek(changeset.Mapper[csBucket].IndexChunkKey(key, timestamp))
    57  	if seekErr != nil {
    58  		return nil, seekErr
    59  	}
    60  
    61  	if k == nil {
    62  		return nil, ethdb.ErrKeyNotFound
    63  	}
    64  	if storage {
    65  		if !bytes.Equal(k[:types.AddressLength], key[:types.AddressLength]) ||
    66  			!bytes.Equal(k[types.AddressLength:types.AddressLength+types.HashLength], key[types.AddressLength+types.IncarnationLength:]) {
    67  			return nil, ethdb.ErrKeyNotFound
    68  		}
    69  	} else {
    70  		if !bytes.HasPrefix(k, key) {
    71  			return nil, ethdb.ErrKeyNotFound
    72  		}
    73  	}
    74  	index := roaring64.New()
    75  	if _, err := index.ReadFrom(bytes.NewReader(v)); err != nil {
    76  		return nil, err
    77  	}
    78  	found, ok := bitmapdb.SeekInBitmap64(index, timestamp)
    79  	changeSetBlock := found
    80  
    81  	var data []byte
    82  	var err error
    83  	if ok {
    84  		data, err = changeset.Mapper[csBucket].Find(changesC, changeSetBlock, key)
    85  		if err != nil {
    86  			if !errors.Is(err, changeset.ErrNotFound) {
    87  				return nil, fmt.Errorf("finding %x in the changeset %d: %w", key, changeSetBlock, err)
    88  			}
    89  			return nil, ethdb.ErrKeyNotFound
    90  		}
    91  	} else {
    92  		return nil, ethdb.ErrKeyNotFound
    93  	}
    94  
    95  	//restore codehash
    96  	if !storage {
    97  		var acc account.StateAccount
    98  		if err := acc.DecodeForStorage(data); err != nil {
    99  			return nil, err
   100  		}
   101  		if acc.Incarnation > 0 && acc.IsEmptyCodeHash() {
   102  			var codeHash []byte
   103  			var err error
   104  			codeHash, err = tx.GetOne(modules.PlainContractCode, modules.PlainGenerateStoragePrefix(key, acc.Incarnation))
   105  			if err != nil {
   106  				return nil, err
   107  			}
   108  			if len(codeHash) > 0 {
   109  				acc.CodeHash.SetBytes(codeHash)
   110  			}
   111  			data = make([]byte, acc.EncodingLengthForStorage())
   112  			acc.EncodeForStorage(data)
   113  		}
   114  		return data, nil
   115  	}
   116  
   117  	return data, nil
   118  }
   119  
   120  // startKey is the concatenation of address and incarnation (BigEndian 8 byte)
   121  func WalkAsOfStorage(tx kv.Tx, address types.Address, incarnation uint16, startLocation types.Hash, timestamp uint64, walker func(k1, k2, v []byte) (bool, error)) error {
   122  	var startkey = make([]byte, types.AddressLength+types.IncarnationLength+types.HashLength)
   123  	copy(startkey, address.Bytes())
   124  	binary.BigEndian.PutUint16(startkey[types.AddressLength:], incarnation)
   125  	copy(startkey[types.AddressLength+types.IncarnationLength:], startLocation.Bytes())
   126  
   127  	var startkeyNoInc = make([]byte, types.AddressLength+types.HashLength)
   128  	copy(startkeyNoInc, address.Bytes())
   129  	copy(startkeyNoInc[types.AddressLength:], startLocation.Bytes())
   130  
   131  	//for storage
   132  	mCursor, err := tx.Cursor(modules.Storage)
   133  	if err != nil {
   134  		return err
   135  	}
   136  	defer mCursor.Close()
   137  	mainCursor := ethdb.NewSplitCursor(
   138  		mCursor,
   139  		startkey,
   140  		8*(types.AddressLength+types.IncarnationLength),
   141  		types.AddressLength,                                          /* part1end */
   142  		types.AddressLength+types.IncarnationLength,                  /* part2start */
   143  		types.AddressLength+types.IncarnationLength+types.HashLength, /* part3start */
   144  	)
   145  
   146  	//for historic data
   147  	shCursor, err := tx.Cursor(modules.StorageHistory)
   148  	if err != nil {
   149  		return err
   150  	}
   151  	defer shCursor.Close()
   152  	var hCursor = ethdb.NewSplitCursor(
   153  		shCursor,
   154  		startkeyNoInc,
   155  		8*types.AddressLength,
   156  		types.AddressLength,                  /* part1end */
   157  		types.AddressLength,                  /* part2start */
   158  		types.AddressLength+types.HashLength, /* part3start */
   159  	)
   160  	csCursor, err := tx.CursorDupSort(modules.StorageChangeSet)
   161  	if err != nil {
   162  		return err
   163  	}
   164  	defer csCursor.Close()
   165  
   166  	addr, loc, _, v, err1 := mainCursor.Seek()
   167  	if err1 != nil {
   168  		return err1
   169  	}
   170  
   171  	hAddr, hLoc, tsEnc, hV, err2 := hCursor.Seek()
   172  	if err2 != nil {
   173  		return err2
   174  	}
   175  	for hLoc != nil && binary.BigEndian.Uint64(tsEnc) < timestamp {
   176  		if hAddr, hLoc, tsEnc, hV, err2 = hCursor.Next(); err2 != nil {
   177  			return err2
   178  		}
   179  	}
   180  	goOn := true
   181  	for goOn {
   182  		cmp, br := types.KeyCmp(addr, hAddr)
   183  		if br {
   184  			break
   185  		}
   186  		if cmp == 0 {
   187  			cmp, br = types.KeyCmp(loc, hLoc)
   188  		}
   189  		if br {
   190  			break
   191  		}
   192  
   193  		//next key in state
   194  		if cmp < 0 {
   195  			goOn, err = walker(addr, loc, v)
   196  		} else {
   197  			index := roaring64.New()
   198  			if _, err = index.ReadFrom(bytes.NewReader(hV)); err != nil {
   199  				return err
   200  			}
   201  			found, ok := bitmapdb.SeekInBitmap64(index, timestamp)
   202  			changeSetBlock := found
   203  
   204  			if ok {
   205  				// Extract value from the changeSet
   206  				csKey := make([]byte, 8+types.AddressLength+types.IncarnationLength)
   207  				copy(csKey, modules.EncodeBlockNumber(changeSetBlock))
   208  				copy(csKey[8:], address[:]) // address + incarnation
   209  				binary.BigEndian.PutUint16(csKey[8+types.AddressLength:], incarnation)
   210  				kData := csKey
   211  				data, err3 := csCursor.SeekBothRange(csKey, hLoc)
   212  				if err3 != nil {
   213  					return err3
   214  				}
   215  				if !bytes.Equal(kData, csKey) || !bytes.HasPrefix(data, hLoc) {
   216  					return fmt.Errorf("inconsistent storage changeset and history kData %x, csKey %x, data %x, hLoc %x", kData, csKey, data, hLoc)
   217  				}
   218  				data = data[types.HashLength:]
   219  				if len(data) > 0 { // Skip deleted entries
   220  					goOn, err = walker(hAddr, hLoc, data)
   221  				}
   222  			} else if cmp == 0 {
   223  				goOn, err = walker(addr, loc, v)
   224  			}
   225  		}
   226  		if err != nil {
   227  			return err
   228  		}
   229  		if goOn {
   230  			if cmp <= 0 {
   231  				if addr, loc, _, v, err1 = mainCursor.Next(); err1 != nil {
   232  					return err1
   233  				}
   234  			}
   235  			if cmp >= 0 {
   236  				hLoc0 := hLoc
   237  				for hLoc != nil && (bytes.Equal(hLoc0, hLoc) || binary.BigEndian.Uint64(tsEnc) < timestamp) {
   238  					if hAddr, hLoc, tsEnc, hV, err2 = hCursor.Next(); err2 != nil {
   239  						return err2
   240  					}
   241  				}
   242  			}
   243  		}
   244  	}
   245  	return nil
   246  }
   247  
   248  func WalkAsOfAccounts(tx kv.Tx, startAddress types.Address, timestamp uint64, walker func(k []byte, v []byte) (bool, error)) error {
   249  	mainCursor, err := tx.Cursor(modules.Account)
   250  	if err != nil {
   251  		return err
   252  	}
   253  	defer mainCursor.Close()
   254  	ahCursor, err := tx.Cursor(modules.AccountsHistory)
   255  	if err != nil {
   256  		return err
   257  	}
   258  	defer ahCursor.Close()
   259  	var hCursor = ethdb.NewSplitCursor(
   260  		ahCursor,
   261  		startAddress.Bytes(),
   262  		0,                     /* fixedBits */
   263  		types.AddressLength,   /* part1end */
   264  		types.AddressLength,   /* part2start */
   265  		types.AddressLength+8, /* part3start */
   266  	)
   267  	csCursor, err := tx.CursorDupSort(modules.AccountChangeSet)
   268  	if err != nil {
   269  		return err
   270  	}
   271  	defer csCursor.Close()
   272  
   273  	k, v, err1 := mainCursor.Seek(startAddress.Bytes())
   274  	if err1 != nil {
   275  		return err1
   276  	}
   277  	for k != nil && len(k) > types.AddressLength {
   278  		k, v, err1 = mainCursor.Next()
   279  		if err1 != nil {
   280  			return err1
   281  		}
   282  	}
   283  	hK, tsEnc, _, hV, err2 := hCursor.Seek()
   284  	if err2 != nil {
   285  		return err2
   286  	}
   287  	for hK != nil && binary.BigEndian.Uint64(tsEnc) < timestamp {
   288  		hK, tsEnc, _, hV, err2 = hCursor.Next()
   289  		if err2 != nil {
   290  			return err2
   291  		}
   292  	}
   293  
   294  	goOn := true
   295  	for goOn {
   296  		//exit or next conditions
   297  		cmp, br := types.KeyCmp(k, hK)
   298  		if br {
   299  			break
   300  		}
   301  		if cmp < 0 {
   302  			goOn, err = walker(k, v)
   303  		} else {
   304  			index := roaring64.New()
   305  			_, err = index.ReadFrom(bytes.NewReader(hV))
   306  			if err != nil {
   307  				return err
   308  			}
   309  			found, ok := bitmapdb.SeekInBitmap64(index, timestamp)
   310  			changeSetBlock := found
   311  			if ok {
   312  				// Extract value from the changeSet
   313  				csKey := modules.EncodeBlockNumber(changeSetBlock)
   314  				kData := csKey
   315  				data, err3 := csCursor.SeekBothRange(csKey, hK)
   316  				if err3 != nil {
   317  					return err3
   318  				}
   319  				if !bytes.Equal(kData, csKey) || !bytes.HasPrefix(data, hK) {
   320  					return fmt.Errorf("inconsistent account history and changesets, kData %x, csKey %x, data %x, hK %x", kData, csKey, data, hK)
   321  				}
   322  				data = data[types.AddressLength:]
   323  				if len(data) > 0 { // Skip accounts did not exist
   324  					goOn, err = walker(hK, data)
   325  				}
   326  			} else if cmp == 0 {
   327  				goOn, err = walker(k, v)
   328  			}
   329  		}
   330  		if err != nil {
   331  			return err
   332  		}
   333  		if goOn {
   334  			if cmp <= 0 {
   335  				k, v, err1 = mainCursor.Next()
   336  				if err1 != nil {
   337  					return err1
   338  				}
   339  				for k != nil && len(k) > types.AddressLength {
   340  					k, v, err1 = mainCursor.Next()
   341  					if err1 != nil {
   342  						return err1
   343  					}
   344  				}
   345  			}
   346  			if cmp >= 0 {
   347  				hK0 := hK
   348  				for hK != nil && (bytes.Equal(hK0, hK) || binary.BigEndian.Uint64(tsEnc) < timestamp) {
   349  					hK, tsEnc, _, hV, err1 = hCursor.Next()
   350  					if err1 != nil {
   351  						return err1
   352  					}
   353  				}
   354  			}
   355  		}
   356  	}
   357  	return err
   358  
   359  }