github.com/ava-labs/avalanchego@v1.11.11/vms/example/xsvm/state/storage.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package state
     5  
     6  import (
     7  	"errors"
     8  
     9  	"github.com/ava-labs/avalanchego/database"
    10  	"github.com/ava-labs/avalanchego/ids"
    11  	"github.com/ava-labs/avalanchego/utils/math"
    12  	"github.com/ava-labs/avalanchego/vms/platformvm/warp"
    13  )
    14  
    15  var (
    16  	errWrongNonce          = errors.New("wrong nonce")
    17  	errInsufficientBalance = errors.New("insufficient balance")
    18  )
    19  
    20  /*
    21   * VMDB
    22   * |-- initializedKey -> nil
    23   * |-. blocks
    24   * | |-- lastAcceptedKey -> blockID
    25   * | |-- height -> blockID
    26   * | '-- blockID -> block bytes
    27   * |-. addresses
    28   * | '-- addressID -> nonce
    29   * | '-- addressID + chainID -> balance
    30   * |-. chains
    31   * | |-- chainID -> balance
    32   * | '-- chainID + loanID -> nil
    33   * '-. message
    34   *   '-- txID -> message bytes
    35   */
    36  
    37  // Chain state
    38  
    39  func IsInitialized(db database.KeyValueReader) (bool, error) {
    40  	return db.Has(initializedKey)
    41  }
    42  
    43  func SetInitialized(db database.KeyValueWriter) error {
    44  	return db.Put(initializedKey, nil)
    45  }
    46  
    47  // Block state
    48  
    49  func GetLastAccepted(db database.KeyValueReader) (ids.ID, error) {
    50  	return database.GetID(db, blockPrefix)
    51  }
    52  
    53  func SetLastAccepted(db database.KeyValueWriter, blkID ids.ID) error {
    54  	return database.PutID(db, blockPrefix, blkID)
    55  }
    56  
    57  func GetBlockIDByHeight(db database.KeyValueReader, height uint64) (ids.ID, error) {
    58  	key := Flatten(blockPrefix, database.PackUInt64(height))
    59  	return database.GetID(db, key)
    60  }
    61  
    62  func GetBlock(db database.KeyValueReader, blkID ids.ID) ([]byte, error) {
    63  	key := Flatten(blockPrefix, blkID[:])
    64  	return db.Get(key)
    65  }
    66  
    67  func AddBlock(db database.KeyValueWriter, height uint64, blkID ids.ID, blk []byte) error {
    68  	heightToIDKey := Flatten(blockPrefix, database.PackUInt64(height))
    69  	if err := database.PutID(db, heightToIDKey, blkID); err != nil {
    70  		return err
    71  	}
    72  	idToBlockKey := Flatten(blockPrefix, blkID[:])
    73  	return db.Put(idToBlockKey, blk)
    74  }
    75  
    76  // Address state
    77  
    78  func GetNonce(db database.KeyValueReader, address ids.ShortID) (uint64, error) {
    79  	key := Flatten(addressPrefix, address[:])
    80  	nonce, err := database.GetUInt64(db, key)
    81  	if errors.Is(err, database.ErrNotFound) {
    82  		return 0, nil
    83  	}
    84  	return nonce, err
    85  }
    86  
    87  func SetNonce(db database.KeyValueWriter, address ids.ShortID, nonce uint64) error {
    88  	key := Flatten(addressPrefix, address[:])
    89  	return database.PutUInt64(db, key, nonce)
    90  }
    91  
    92  func IncrementNonce(db database.KeyValueReaderWriter, address ids.ShortID, nonce uint64) error {
    93  	expectedNonce, err := GetNonce(db, address)
    94  	if err != nil {
    95  		return err
    96  	}
    97  	if nonce != expectedNonce {
    98  		return errWrongNonce
    99  	}
   100  	return SetNonce(db, address, nonce+1)
   101  }
   102  
   103  func GetBalance(db database.KeyValueReader, address ids.ShortID, chainID ids.ID) (uint64, error) {
   104  	key := Flatten(addressPrefix, address[:], chainID[:])
   105  	balance, err := database.GetUInt64(db, key)
   106  	if errors.Is(err, database.ErrNotFound) {
   107  		return 0, nil
   108  	}
   109  	return balance, err
   110  }
   111  
   112  func SetBalance(db database.KeyValueWriterDeleter, address ids.ShortID, chainID ids.ID, balance uint64) error {
   113  	key := Flatten(addressPrefix, address[:], chainID[:])
   114  	if balance == 0 {
   115  		return db.Delete(key)
   116  	}
   117  	return database.PutUInt64(db, key, balance)
   118  }
   119  
   120  func DecreaseBalance(db database.KeyValueReaderWriterDeleter, address ids.ShortID, chainID ids.ID, amount uint64) error {
   121  	balance, err := GetBalance(db, address, chainID)
   122  	if err != nil {
   123  		return err
   124  	}
   125  	if balance < amount {
   126  		return errInsufficientBalance
   127  	}
   128  	return SetBalance(db, address, chainID, balance-amount)
   129  }
   130  
   131  func IncreaseBalance(db database.KeyValueReaderWriterDeleter, address ids.ShortID, chainID ids.ID, amount uint64) error {
   132  	balance, err := GetBalance(db, address, chainID)
   133  	if err != nil {
   134  		return err
   135  	}
   136  	balance, err = math.Add(balance, amount)
   137  	if err != nil {
   138  		return err
   139  	}
   140  	return SetBalance(db, address, chainID, balance)
   141  }
   142  
   143  // Chain state
   144  
   145  func HasLoanID(db database.KeyValueReader, chainID ids.ID, loanID ids.ID) (bool, error) {
   146  	key := Flatten(chainPrefix, chainID[:], loanID[:])
   147  	return db.Has(key)
   148  }
   149  
   150  func AddLoanID(db database.KeyValueWriter, chainID ids.ID, loanID ids.ID) error {
   151  	key := Flatten(chainPrefix, chainID[:], loanID[:])
   152  	return db.Put(key, nil)
   153  }
   154  
   155  func GetLoan(db database.KeyValueReader, chainID ids.ID) (uint64, error) {
   156  	key := Flatten(chainPrefix, chainID[:])
   157  	balance, err := database.GetUInt64(db, key)
   158  	if errors.Is(err, database.ErrNotFound) {
   159  		return 0, nil
   160  	}
   161  	return balance, err
   162  }
   163  
   164  func SetLoan(db database.KeyValueWriterDeleter, chainID ids.ID, balance uint64) error {
   165  	key := Flatten(chainPrefix, chainID[:])
   166  	if balance == 0 {
   167  		return db.Delete(key)
   168  	}
   169  	return database.PutUInt64(db, key, balance)
   170  }
   171  
   172  func DecreaseLoan(db database.KeyValueReaderWriterDeleter, chainID ids.ID, amount uint64) error {
   173  	balance, err := GetLoan(db, chainID)
   174  	if err != nil {
   175  		return err
   176  	}
   177  	if balance < amount {
   178  		return errInsufficientBalance
   179  	}
   180  	return SetLoan(db, chainID, balance-amount)
   181  }
   182  
   183  func IncreaseLoan(db database.KeyValueReaderWriterDeleter, chainID ids.ID, amount uint64) error {
   184  	balance, err := GetLoan(db, chainID)
   185  	if err != nil {
   186  		return err
   187  	}
   188  	balance, err = math.Add(balance, amount)
   189  	if err != nil {
   190  		return err
   191  	}
   192  	return SetLoan(db, chainID, balance)
   193  }
   194  
   195  // Message state
   196  
   197  func GetMessage(db database.KeyValueReader, txID ids.ID) (*warp.UnsignedMessage, error) {
   198  	key := Flatten(messagePrefix, txID[:])
   199  	bytes, err := db.Get(key)
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  	return warp.ParseUnsignedMessage(bytes)
   204  }
   205  
   206  func SetMessage(db database.KeyValueWriter, txID ids.ID, message *warp.UnsignedMessage) error {
   207  	key := Flatten(messagePrefix, txID[:])
   208  	bytes := message.Bytes()
   209  	return db.Put(key, bytes)
   210  }