github.com/amazechain/amc@v0.1.3/modules/changeset/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  	"fmt"
    23  	"github.com/amazechain/amc/common/types"
    24  	"github.com/amazechain/amc/modules"
    25  	"github.com/amazechain/amc/modules/ethdb"
    26  	"math"
    27  	"reflect"
    28  
    29  	"github.com/ledgerwatch/erigon-lib/kv"
    30  )
    31  
    32  func NewChangeSet() *ChangeSet {
    33  	return &ChangeSet{
    34  		Changes: make([]Change, 0),
    35  	}
    36  }
    37  
    38  type Change struct {
    39  	Key   []byte
    40  	Value []byte
    41  }
    42  
    43  // ChangeSet is a map with keys of the same size.
    44  // Both keys and values are byte strings.
    45  type ChangeSet struct {
    46  	// Invariant: all keys are of the same size.
    47  	Changes []Change
    48  	keyLen  int
    49  }
    50  
    51  // BEGIN sort.Interface
    52  
    53  func (s *ChangeSet) Len() int {
    54  	return len(s.Changes)
    55  }
    56  
    57  func (s *ChangeSet) Swap(i, j int) {
    58  	s.Changes[i], s.Changes[j] = s.Changes[j], s.Changes[i]
    59  }
    60  
    61  func (s *ChangeSet) Less(i, j int) bool {
    62  	cmp := bytes.Compare(s.Changes[i].Key, s.Changes[j].Key)
    63  	if cmp == 0 {
    64  		cmp = bytes.Compare(s.Changes[i].Value, s.Changes[j].Value)
    65  	}
    66  	return cmp < 0
    67  }
    68  
    69  // END sort.Interface
    70  func (s *ChangeSet) KeySize() int {
    71  	if s.keyLen != 0 {
    72  		return s.keyLen
    73  	}
    74  	for _, c := range s.Changes {
    75  		return len(c.Key)
    76  	}
    77  	return 0
    78  }
    79  
    80  func (s *ChangeSet) checkKeySize(key []byte) error {
    81  	if (s.Len() == 0 && s.KeySize() == 0) || (len(key) == s.KeySize() && len(key) > 0) {
    82  		return nil
    83  	}
    84  
    85  	return fmt.Errorf("wrong key size in AccountChangeSet: expected %d, actual %d", s.KeySize(), len(key))
    86  }
    87  
    88  // Add adds a new entry to the AccountChangeSet.
    89  // One must not add an existing key
    90  // and may add keys only of the same size.
    91  func (s *ChangeSet) Add(key []byte, value []byte) error {
    92  	if err := s.checkKeySize(key); err != nil {
    93  		return err
    94  	}
    95  
    96  	s.Changes = append(s.Changes, Change{
    97  		Key:   key,
    98  		Value: value,
    99  	})
   100  	return nil
   101  }
   102  
   103  func (s *ChangeSet) ChangedKeys() map[string]struct{} {
   104  	m := make(map[string]struct{}, len(s.Changes))
   105  	for i := range s.Changes {
   106  		m[string(s.Changes[i].Key)] = struct{}{}
   107  	}
   108  	return m
   109  }
   110  
   111  func (s *ChangeSet) Equals(s2 *ChangeSet) bool {
   112  	return reflect.DeepEqual(s.Changes, s2.Changes)
   113  }
   114  
   115  func (s *ChangeSet) String() string {
   116  	str := ""
   117  	for _, v := range s.Changes {
   118  		str += fmt.Sprintf("%v %s : %s\n", len(v.Key), types.Bytes2Hex(v.Key), string(v.Value))
   119  	}
   120  	return str
   121  }
   122  
   123  // Encoded Method
   124  func FromDBFormat(dbKey, dbValue []byte) (uint64, []byte, []byte, error) {
   125  	if len(dbKey) == 8 {
   126  		return DecodeAccounts(dbKey, dbValue)
   127  	} else {
   128  		return DecodeStorage(dbKey, dbValue)
   129  	}
   130  }
   131  
   132  func AvailableFrom(tx kv.Tx) (uint64, error) {
   133  	c, err := tx.Cursor(modules.AccountChangeSet)
   134  	if err != nil {
   135  		return math.MaxUint64, err
   136  	}
   137  	defer c.Close()
   138  	k, _, err := c.First()
   139  	if err != nil {
   140  		return math.MaxUint64, err
   141  	}
   142  	if len(k) == 0 {
   143  		return math.MaxUint64, nil
   144  	}
   145  	return binary.BigEndian.Uint64(k), nil
   146  }
   147  func AvailableStorageFrom(tx kv.Tx) (uint64, error) {
   148  	c, err := tx.Cursor(modules.StorageChangeSet)
   149  	if err != nil {
   150  		return math.MaxUint64, err
   151  	}
   152  	defer c.Close()
   153  	k, _, err := c.First()
   154  	if err != nil {
   155  		return math.MaxUint64, err
   156  	}
   157  	if len(k) == 0 {
   158  		return math.MaxUint64, nil
   159  	}
   160  	return binary.BigEndian.Uint64(k), nil
   161  }
   162  
   163  // [from:to)
   164  func ForRange(db kv.Tx, bucket string, from, to uint64, walker func(blockN uint64, k, v []byte) error) error {
   165  	var blockN uint64
   166  	c, err := db.Cursor(bucket)
   167  	if err != nil {
   168  		return err
   169  	}
   170  	defer c.Close()
   171  	return ethdb.Walk(c, modules.EncodeBlockNumber(from), 0, func(k, v []byte) (bool, error) {
   172  		var err error
   173  		blockN, k, v, err = FromDBFormat(k, v)
   174  		if err != nil {
   175  			return false, err
   176  		}
   177  		if blockN >= to {
   178  			return false, nil
   179  		}
   180  		if err = walker(blockN, k, v); err != nil {
   181  			return false, err
   182  		}
   183  		return true, nil
   184  	})
   185  }
   186  func ForEach(db kv.Tx, bucket string, startkey []byte, walker func(blockN uint64, k, v []byte) error) error {
   187  	var blockN uint64
   188  	return db.ForEach(bucket, startkey, func(k, v []byte) error {
   189  		var err error
   190  		blockN, k, v, err = FromDBFormat(k, v)
   191  		if err != nil {
   192  			return err
   193  		}
   194  		return walker(blockN, k, v)
   195  	})
   196  }
   197  func ForPrefix(db kv.Tx, bucket string, startkey []byte, walker func(blockN uint64, k, v []byte) error) error {
   198  	var blockN uint64
   199  	return db.ForPrefix(bucket, startkey, func(k, v []byte) error {
   200  		var err error
   201  		blockN, k, v, err = FromDBFormat(k, v)
   202  		if err != nil {
   203  			return err
   204  		}
   205  		return walker(blockN, k, v)
   206  	})
   207  }
   208  
   209  func Truncate(tx kv.RwTx, from uint64) error {
   210  	keyStart := modules.EncodeBlockNumber(from)
   211  
   212  	{
   213  		c, err := tx.RwCursorDupSort(modules.AccountChangeSet)
   214  		if err != nil {
   215  			return err
   216  		}
   217  		defer c.Close()
   218  		for k, _, err := c.Seek(keyStart); k != nil; k, _, err = c.NextNoDup() {
   219  			if err != nil {
   220  				return err
   221  			}
   222  			err = c.DeleteCurrentDuplicates()
   223  			if err != nil {
   224  				return err
   225  			}
   226  		}
   227  	}
   228  	{
   229  		c, err := tx.RwCursorDupSort(modules.StorageChangeSet)
   230  		if err != nil {
   231  			return err
   232  		}
   233  		defer c.Close()
   234  		for k, _, err := c.Seek(keyStart); k != nil; k, _, err = c.NextNoDup() {
   235  			if err != nil {
   236  				return err
   237  			}
   238  			err = c.DeleteCurrentDuplicates()
   239  			if err != nil {
   240  				return err
   241  			}
   242  		}
   243  	}
   244  	return nil
   245  }
   246  
   247  var Mapper = map[string]struct {
   248  	IndexBucket   string
   249  	IndexChunkKey func([]byte, uint64) []byte
   250  	Find          func(cursor kv.CursorDupSort, blockNumber uint64, key []byte) ([]byte, error)
   251  	New           func() *ChangeSet
   252  	Encode        Encoder
   253  	Decode        Decoder
   254  }{
   255  	modules.AccountChangeSet: {
   256  		IndexBucket:   modules.AccountsHistory,
   257  		IndexChunkKey: modules.AccountIndexChunkKey,
   258  		New:           NewAccountChangeSet,
   259  		Find:          FindAccount,
   260  		Encode:        EncodeAccounts,
   261  		Decode:        DecodeAccounts,
   262  	},
   263  	modules.StorageChangeSet: {
   264  		IndexBucket:   modules.StorageHistory,
   265  		IndexChunkKey: modules.StorageIndexChunkKey,
   266  		Find:          FindStorage,
   267  		New:           NewStorageChangeSet,
   268  		Encode:        EncodeStorage,
   269  		Decode:        DecodeStorage,
   270  	},
   271  }