github.com/amazechain/amc@v0.1.3/modules/changeset/storage_changeset.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 changeset
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/binary"
    22  	"errors"
    23  	"fmt"
    24  	"github.com/amazechain/amc/modules"
    25  	"sort"
    26  
    27  	libcommon "github.com/ledgerwatch/erigon-lib/common"
    28  	"github.com/ledgerwatch/erigon-lib/common/length"
    29  	"github.com/ledgerwatch/erigon-lib/etl"
    30  	"github.com/ledgerwatch/erigon-lib/kv"
    31  )
    32  
    33  const (
    34  	DefaultIncarnation = uint64(1)
    35  )
    36  
    37  var (
    38  	ErrNotFound = errors.New("not found")
    39  )
    40  
    41  func NewStorageChangeSet() *ChangeSet {
    42  	return &ChangeSet{
    43  		Changes: make([]Change, 0),
    44  		keyLen:  length.Addr + length.Hash + modules.Incarnation,
    45  	}
    46  }
    47  
    48  func EncodeStorage(blockN uint64, s *ChangeSet, f func(k, v []byte) error) error {
    49  	sort.Sort(s)
    50  	keyPart := length.Addr + modules.Incarnation
    51  	for _, cs := range s.Changes {
    52  		newK := make([]byte, length.BlockNum+keyPart)
    53  		binary.BigEndian.PutUint64(newK, blockN)
    54  		copy(newK[8:], cs.Key[:keyPart])
    55  		newV := make([]byte, 0, length.Hash+len(cs.Value))
    56  		newV = append(append(newV, cs.Key[keyPart:]...), cs.Value...)
    57  		if err := f(newK, newV); err != nil {
    58  			return err
    59  		}
    60  	}
    61  	return nil
    62  }
    63  
    64  func DecodeStorage(dbKey, dbValue []byte) (uint64, []byte, []byte, error) {
    65  	blockN := binary.BigEndian.Uint64(dbKey)
    66  	if len(dbValue) < length.Hash {
    67  		return 0, nil, nil, fmt.Errorf("storage changes purged for block %d", blockN)
    68  	}
    69  	k := make([]byte, length.Addr+modules.Incarnation+length.Hash)
    70  	dbKey = dbKey[length.BlockNum:] // remove BlockN bytes
    71  	copy(k, dbKey)
    72  	copy(k[len(dbKey):], dbValue[:length.Hash])
    73  	v := dbValue[length.Hash:]
    74  	if len(v) == 0 {
    75  		v = nil
    76  	}
    77  
    78  	return blockN, k, v, nil
    79  }
    80  
    81  func FindStorage(c kv.CursorDupSort, blockNumber uint64, k []byte) ([]byte, error) {
    82  	addWithInc, loc := k[:length.Addr+modules.Incarnation], k[length.Addr+modules.Incarnation:]
    83  	seek := make([]byte, length.BlockNum+length.Addr+modules.Incarnation)
    84  	binary.BigEndian.PutUint64(seek, blockNumber)
    85  	copy(seek[8:], addWithInc)
    86  	v, err := c.SeekBothRange(seek, loc)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	if !bytes.HasPrefix(v, loc) {
    91  		return nil, ErrNotFound
    92  	}
    93  	return v[length.Hash:], nil
    94  }
    95  
    96  // RewindDataPlain generates rewind data for all plain buckets between the timestamp
    97  // timestapSrc is the current timestamp, and timestamp Dst is where we rewind
    98  func RewindData(db kv.Tx, timestampSrc, timestampDst uint64, changes *etl.Collector, quit <-chan struct{}) error {
    99  	if err := walkAndCollect(
   100  		changes.Collect,
   101  		db, modules.AccountChangeSet,
   102  		timestampDst+1, timestampSrc,
   103  		quit,
   104  	); err != nil {
   105  		return err
   106  	}
   107  
   108  	if err := walkAndCollect(
   109  		changes.Collect,
   110  		db, modules.StorageChangeSet,
   111  		timestampDst+1, timestampSrc,
   112  		quit,
   113  	); err != nil {
   114  		return err
   115  	}
   116  
   117  	return nil
   118  }
   119  
   120  func walkAndCollect(collectorFunc func([]byte, []byte) error, db kv.Tx, bucket string, timestampDst, timestampSrc uint64, quit <-chan struct{}) error {
   121  	return ForRange(db, bucket, timestampDst, timestampSrc+1, func(bl uint64, k, v []byte) error {
   122  		if err := libcommon.Stopped(quit); err != nil {
   123  			return err
   124  		}
   125  		if innerErr := collectorFunc(libcommon.Copy(k), libcommon.Copy(v)); innerErr != nil {
   126  			return innerErr
   127  		}
   128  		return nil
   129  	})
   130  }