github.com/ava-labs/avalanchego@v1.11.11/vms/platformvm/state/diff.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  	"fmt"
     9  	"time"
    10  
    11  	"github.com/ava-labs/avalanchego/database"
    12  	"github.com/ava-labs/avalanchego/ids"
    13  	"github.com/ava-labs/avalanchego/utils/iterator"
    14  	"github.com/ava-labs/avalanchego/vms/components/avax"
    15  	"github.com/ava-labs/avalanchego/vms/components/gas"
    16  	"github.com/ava-labs/avalanchego/vms/platformvm/fx"
    17  	"github.com/ava-labs/avalanchego/vms/platformvm/status"
    18  	"github.com/ava-labs/avalanchego/vms/platformvm/txs"
    19  )
    20  
    21  var (
    22  	_ Diff     = (*diff)(nil)
    23  	_ Versions = stateGetter{}
    24  
    25  	ErrMissingParentState = errors.New("missing parent state")
    26  )
    27  
    28  type Diff interface {
    29  	Chain
    30  
    31  	Apply(Chain) error
    32  }
    33  
    34  type diff struct {
    35  	parentID      ids.ID
    36  	stateVersions Versions
    37  
    38  	timestamp time.Time
    39  	feeState  gas.State
    40  
    41  	// Subnet ID --> supply of native asset of the subnet
    42  	currentSupply map[ids.ID]uint64
    43  
    44  	currentStakerDiffs diffStakers
    45  	// map of subnetID -> nodeID -> total accrued delegatee rewards
    46  	modifiedDelegateeRewards map[ids.ID]map[ids.NodeID]uint64
    47  	pendingStakerDiffs       diffStakers
    48  
    49  	addedSubnetIDs []ids.ID
    50  	// Subnet ID --> Owner of the subnet
    51  	subnetOwners map[ids.ID]fx.Owner
    52  	// Subnet ID --> Manager of the subnet
    53  	subnetManagers map[ids.ID]chainIDAndAddr
    54  	// Subnet ID --> Tx that transforms the subnet
    55  	transformedSubnets map[ids.ID]*txs.Tx
    56  
    57  	addedChains map[ids.ID][]*txs.Tx
    58  
    59  	addedRewardUTXOs map[ids.ID][]*avax.UTXO
    60  
    61  	addedTxs map[ids.ID]*txAndStatus
    62  
    63  	// map of modified UTXOID -> *UTXO if the UTXO is nil, it has been removed
    64  	modifiedUTXOs map[ids.ID]*avax.UTXO
    65  }
    66  
    67  func NewDiff(
    68  	parentID ids.ID,
    69  	stateVersions Versions,
    70  ) (Diff, error) {
    71  	parentState, ok := stateVersions.GetState(parentID)
    72  	if !ok {
    73  		return nil, fmt.Errorf("%w: %s", ErrMissingParentState, parentID)
    74  	}
    75  	return &diff{
    76  		parentID:       parentID,
    77  		stateVersions:  stateVersions,
    78  		timestamp:      parentState.GetTimestamp(),
    79  		feeState:       parentState.GetFeeState(),
    80  		subnetOwners:   make(map[ids.ID]fx.Owner),
    81  		subnetManagers: make(map[ids.ID]chainIDAndAddr),
    82  	}, nil
    83  }
    84  
    85  type stateGetter struct {
    86  	state Chain
    87  }
    88  
    89  func (s stateGetter) GetState(ids.ID) (Chain, bool) {
    90  	return s.state, true
    91  }
    92  
    93  func NewDiffOn(parentState Chain) (Diff, error) {
    94  	return NewDiff(ids.Empty, stateGetter{
    95  		state: parentState,
    96  	})
    97  }
    98  
    99  func (d *diff) GetTimestamp() time.Time {
   100  	return d.timestamp
   101  }
   102  
   103  func (d *diff) SetTimestamp(timestamp time.Time) {
   104  	d.timestamp = timestamp
   105  }
   106  
   107  func (d *diff) GetFeeState() gas.State {
   108  	return d.feeState
   109  }
   110  
   111  func (d *diff) SetFeeState(feeState gas.State) {
   112  	d.feeState = feeState
   113  }
   114  
   115  func (d *diff) GetCurrentSupply(subnetID ids.ID) (uint64, error) {
   116  	supply, ok := d.currentSupply[subnetID]
   117  	if ok {
   118  		return supply, nil
   119  	}
   120  
   121  	// If the subnet supply wasn't modified in this diff, ask the parent state.
   122  	parentState, ok := d.stateVersions.GetState(d.parentID)
   123  	if !ok {
   124  		return 0, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID)
   125  	}
   126  	return parentState.GetCurrentSupply(subnetID)
   127  }
   128  
   129  func (d *diff) SetCurrentSupply(subnetID ids.ID, currentSupply uint64) {
   130  	if d.currentSupply == nil {
   131  		d.currentSupply = map[ids.ID]uint64{
   132  			subnetID: currentSupply,
   133  		}
   134  	} else {
   135  		d.currentSupply[subnetID] = currentSupply
   136  	}
   137  }
   138  
   139  func (d *diff) GetCurrentValidator(subnetID ids.ID, nodeID ids.NodeID) (*Staker, error) {
   140  	// If the validator was modified in this diff, return the modified
   141  	// validator.
   142  	newValidator, status := d.currentStakerDiffs.GetValidator(subnetID, nodeID)
   143  	switch status {
   144  	case added:
   145  		return newValidator, nil
   146  	case deleted:
   147  		return nil, database.ErrNotFound
   148  	default:
   149  		// If the validator wasn't modified in this diff, ask the parent state.
   150  		parentState, ok := d.stateVersions.GetState(d.parentID)
   151  		if !ok {
   152  			return nil, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID)
   153  		}
   154  		return parentState.GetCurrentValidator(subnetID, nodeID)
   155  	}
   156  }
   157  
   158  func (d *diff) SetDelegateeReward(subnetID ids.ID, nodeID ids.NodeID, amount uint64) error {
   159  	if d.modifiedDelegateeRewards == nil {
   160  		d.modifiedDelegateeRewards = make(map[ids.ID]map[ids.NodeID]uint64)
   161  	}
   162  	nodes, ok := d.modifiedDelegateeRewards[subnetID]
   163  	if !ok {
   164  		nodes = make(map[ids.NodeID]uint64)
   165  		d.modifiedDelegateeRewards[subnetID] = nodes
   166  	}
   167  	nodes[nodeID] = amount
   168  	return nil
   169  }
   170  
   171  func (d *diff) GetDelegateeReward(subnetID ids.ID, nodeID ids.NodeID) (uint64, error) {
   172  	amount, modified := d.modifiedDelegateeRewards[subnetID][nodeID]
   173  	if modified {
   174  		return amount, nil
   175  	}
   176  	parentState, ok := d.stateVersions.GetState(d.parentID)
   177  	if !ok {
   178  		return 0, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID)
   179  	}
   180  	return parentState.GetDelegateeReward(subnetID, nodeID)
   181  }
   182  
   183  func (d *diff) PutCurrentValidator(staker *Staker) error {
   184  	return d.currentStakerDiffs.PutValidator(staker)
   185  }
   186  
   187  func (d *diff) DeleteCurrentValidator(staker *Staker) {
   188  	d.currentStakerDiffs.DeleteValidator(staker)
   189  }
   190  
   191  func (d *diff) GetCurrentDelegatorIterator(subnetID ids.ID, nodeID ids.NodeID) (iterator.Iterator[*Staker], error) {
   192  	parentState, ok := d.stateVersions.GetState(d.parentID)
   193  	if !ok {
   194  		return nil, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID)
   195  	}
   196  
   197  	parentIterator, err := parentState.GetCurrentDelegatorIterator(subnetID, nodeID)
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  
   202  	return d.currentStakerDiffs.GetDelegatorIterator(parentIterator, subnetID, nodeID), nil
   203  }
   204  
   205  func (d *diff) PutCurrentDelegator(staker *Staker) {
   206  	d.currentStakerDiffs.PutDelegator(staker)
   207  }
   208  
   209  func (d *diff) DeleteCurrentDelegator(staker *Staker) {
   210  	d.currentStakerDiffs.DeleteDelegator(staker)
   211  }
   212  
   213  func (d *diff) GetCurrentStakerIterator() (iterator.Iterator[*Staker], error) {
   214  	parentState, ok := d.stateVersions.GetState(d.parentID)
   215  	if !ok {
   216  		return nil, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID)
   217  	}
   218  
   219  	parentIterator, err := parentState.GetCurrentStakerIterator()
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  
   224  	return d.currentStakerDiffs.GetStakerIterator(parentIterator), nil
   225  }
   226  
   227  func (d *diff) GetPendingValidator(subnetID ids.ID, nodeID ids.NodeID) (*Staker, error) {
   228  	// If the validator was modified in this diff, return the modified
   229  	// validator.
   230  	newValidator, status := d.pendingStakerDiffs.GetValidator(subnetID, nodeID)
   231  	switch status {
   232  	case added:
   233  		return newValidator, nil
   234  	case deleted:
   235  		return nil, database.ErrNotFound
   236  	default:
   237  		// If the validator wasn't modified in this diff, ask the parent state.
   238  		parentState, ok := d.stateVersions.GetState(d.parentID)
   239  		if !ok {
   240  			return nil, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID)
   241  		}
   242  		return parentState.GetPendingValidator(subnetID, nodeID)
   243  	}
   244  }
   245  
   246  func (d *diff) PutPendingValidator(staker *Staker) error {
   247  	return d.pendingStakerDiffs.PutValidator(staker)
   248  }
   249  
   250  func (d *diff) DeletePendingValidator(staker *Staker) {
   251  	d.pendingStakerDiffs.DeleteValidator(staker)
   252  }
   253  
   254  func (d *diff) GetPendingDelegatorIterator(subnetID ids.ID, nodeID ids.NodeID) (iterator.Iterator[*Staker], error) {
   255  	parentState, ok := d.stateVersions.GetState(d.parentID)
   256  	if !ok {
   257  		return nil, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID)
   258  	}
   259  
   260  	parentIterator, err := parentState.GetPendingDelegatorIterator(subnetID, nodeID)
   261  	if err != nil {
   262  		return nil, err
   263  	}
   264  
   265  	return d.pendingStakerDiffs.GetDelegatorIterator(parentIterator, subnetID, nodeID), nil
   266  }
   267  
   268  func (d *diff) PutPendingDelegator(staker *Staker) {
   269  	d.pendingStakerDiffs.PutDelegator(staker)
   270  }
   271  
   272  func (d *diff) DeletePendingDelegator(staker *Staker) {
   273  	d.pendingStakerDiffs.DeleteDelegator(staker)
   274  }
   275  
   276  func (d *diff) GetPendingStakerIterator() (iterator.Iterator[*Staker], error) {
   277  	parentState, ok := d.stateVersions.GetState(d.parentID)
   278  	if !ok {
   279  		return nil, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID)
   280  	}
   281  
   282  	parentIterator, err := parentState.GetPendingStakerIterator()
   283  	if err != nil {
   284  		return nil, err
   285  	}
   286  
   287  	return d.pendingStakerDiffs.GetStakerIterator(parentIterator), nil
   288  }
   289  
   290  func (d *diff) AddSubnet(subnetID ids.ID) {
   291  	d.addedSubnetIDs = append(d.addedSubnetIDs, subnetID)
   292  }
   293  
   294  func (d *diff) GetSubnetOwner(subnetID ids.ID) (fx.Owner, error) {
   295  	owner, exists := d.subnetOwners[subnetID]
   296  	if exists {
   297  		return owner, nil
   298  	}
   299  
   300  	// If the subnet owner was not assigned in this diff, ask the parent state.
   301  	parentState, ok := d.stateVersions.GetState(d.parentID)
   302  	if !ok {
   303  		return nil, ErrMissingParentState
   304  	}
   305  	return parentState.GetSubnetOwner(subnetID)
   306  }
   307  
   308  func (d *diff) SetSubnetOwner(subnetID ids.ID, owner fx.Owner) {
   309  	d.subnetOwners[subnetID] = owner
   310  }
   311  
   312  func (d *diff) GetSubnetManager(subnetID ids.ID) (ids.ID, []byte, error) {
   313  	if manager, exists := d.subnetManagers[subnetID]; exists {
   314  		return manager.ChainID, manager.Addr, nil
   315  	}
   316  
   317  	// If the subnet manager was not assigned in this diff, ask the parent state.
   318  	parentState, ok := d.stateVersions.GetState(d.parentID)
   319  	if !ok {
   320  		return ids.Empty, nil, ErrMissingParentState
   321  	}
   322  	return parentState.GetSubnetManager(subnetID)
   323  }
   324  
   325  func (d *diff) SetSubnetManager(subnetID ids.ID, chainID ids.ID, addr []byte) {
   326  	d.subnetManagers[subnetID] = chainIDAndAddr{
   327  		ChainID: chainID,
   328  		Addr:    addr,
   329  	}
   330  }
   331  
   332  func (d *diff) GetSubnetTransformation(subnetID ids.ID) (*txs.Tx, error) {
   333  	tx, exists := d.transformedSubnets[subnetID]
   334  	if exists {
   335  		return tx, nil
   336  	}
   337  
   338  	// If the subnet wasn't transformed in this diff, ask the parent state.
   339  	parentState, ok := d.stateVersions.GetState(d.parentID)
   340  	if !ok {
   341  		return nil, ErrMissingParentState
   342  	}
   343  	return parentState.GetSubnetTransformation(subnetID)
   344  }
   345  
   346  func (d *diff) AddSubnetTransformation(transformSubnetTxIntf *txs.Tx) {
   347  	transformSubnetTx := transformSubnetTxIntf.Unsigned.(*txs.TransformSubnetTx)
   348  	if d.transformedSubnets == nil {
   349  		d.transformedSubnets = map[ids.ID]*txs.Tx{
   350  			transformSubnetTx.Subnet: transformSubnetTxIntf,
   351  		}
   352  	} else {
   353  		d.transformedSubnets[transformSubnetTx.Subnet] = transformSubnetTxIntf
   354  	}
   355  }
   356  
   357  func (d *diff) AddChain(createChainTx *txs.Tx) {
   358  	tx := createChainTx.Unsigned.(*txs.CreateChainTx)
   359  	if d.addedChains == nil {
   360  		d.addedChains = map[ids.ID][]*txs.Tx{
   361  			tx.SubnetID: {createChainTx},
   362  		}
   363  	} else {
   364  		d.addedChains[tx.SubnetID] = append(d.addedChains[tx.SubnetID], createChainTx)
   365  	}
   366  }
   367  
   368  func (d *diff) GetTx(txID ids.ID) (*txs.Tx, status.Status, error) {
   369  	if tx, exists := d.addedTxs[txID]; exists {
   370  		return tx.tx, tx.status, nil
   371  	}
   372  
   373  	parentState, ok := d.stateVersions.GetState(d.parentID)
   374  	if !ok {
   375  		return nil, status.Unknown, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID)
   376  	}
   377  	return parentState.GetTx(txID)
   378  }
   379  
   380  func (d *diff) AddTx(tx *txs.Tx, status status.Status) {
   381  	txID := tx.ID()
   382  	txStatus := &txAndStatus{
   383  		tx:     tx,
   384  		status: status,
   385  	}
   386  	if d.addedTxs == nil {
   387  		d.addedTxs = map[ids.ID]*txAndStatus{
   388  			txID: txStatus,
   389  		}
   390  	} else {
   391  		d.addedTxs[txID] = txStatus
   392  	}
   393  }
   394  
   395  func (d *diff) AddRewardUTXO(txID ids.ID, utxo *avax.UTXO) {
   396  	if d.addedRewardUTXOs == nil {
   397  		d.addedRewardUTXOs = make(map[ids.ID][]*avax.UTXO)
   398  	}
   399  	d.addedRewardUTXOs[txID] = append(d.addedRewardUTXOs[txID], utxo)
   400  }
   401  
   402  func (d *diff) GetUTXO(utxoID ids.ID) (*avax.UTXO, error) {
   403  	utxo, modified := d.modifiedUTXOs[utxoID]
   404  	if !modified {
   405  		parentState, ok := d.stateVersions.GetState(d.parentID)
   406  		if !ok {
   407  			return nil, fmt.Errorf("%w: %s", ErrMissingParentState, d.parentID)
   408  		}
   409  		return parentState.GetUTXO(utxoID)
   410  	}
   411  	if utxo == nil {
   412  		return nil, database.ErrNotFound
   413  	}
   414  	return utxo, nil
   415  }
   416  
   417  func (d *diff) AddUTXO(utxo *avax.UTXO) {
   418  	if d.modifiedUTXOs == nil {
   419  		d.modifiedUTXOs = map[ids.ID]*avax.UTXO{
   420  			utxo.InputID(): utxo,
   421  		}
   422  	} else {
   423  		d.modifiedUTXOs[utxo.InputID()] = utxo
   424  	}
   425  }
   426  
   427  func (d *diff) DeleteUTXO(utxoID ids.ID) {
   428  	if d.modifiedUTXOs == nil {
   429  		d.modifiedUTXOs = map[ids.ID]*avax.UTXO{
   430  			utxoID: nil,
   431  		}
   432  	} else {
   433  		d.modifiedUTXOs[utxoID] = nil
   434  	}
   435  }
   436  
   437  func (d *diff) Apply(baseState Chain) error {
   438  	baseState.SetTimestamp(d.timestamp)
   439  	baseState.SetFeeState(d.feeState)
   440  	for subnetID, supply := range d.currentSupply {
   441  		baseState.SetCurrentSupply(subnetID, supply)
   442  	}
   443  	for _, subnetValidatorDiffs := range d.currentStakerDiffs.validatorDiffs {
   444  		for _, validatorDiff := range subnetValidatorDiffs {
   445  			switch validatorDiff.validatorStatus {
   446  			case added:
   447  				if err := baseState.PutCurrentValidator(validatorDiff.validator); err != nil {
   448  					return err
   449  				}
   450  			case deleted:
   451  				baseState.DeleteCurrentValidator(validatorDiff.validator)
   452  			}
   453  
   454  			addedDelegatorIterator := iterator.FromTree(validatorDiff.addedDelegators)
   455  			for addedDelegatorIterator.Next() {
   456  				baseState.PutCurrentDelegator(addedDelegatorIterator.Value())
   457  			}
   458  			addedDelegatorIterator.Release()
   459  
   460  			for _, delegator := range validatorDiff.deletedDelegators {
   461  				baseState.DeleteCurrentDelegator(delegator)
   462  			}
   463  		}
   464  	}
   465  	for subnetID, nodes := range d.modifiedDelegateeRewards {
   466  		for nodeID, amount := range nodes {
   467  			if err := baseState.SetDelegateeReward(subnetID, nodeID, amount); err != nil {
   468  				return err
   469  			}
   470  		}
   471  	}
   472  	for _, subnetValidatorDiffs := range d.pendingStakerDiffs.validatorDiffs {
   473  		for _, validatorDiff := range subnetValidatorDiffs {
   474  			switch validatorDiff.validatorStatus {
   475  			case added:
   476  				if err := baseState.PutPendingValidator(validatorDiff.validator); err != nil {
   477  					return err
   478  				}
   479  			case deleted:
   480  				baseState.DeletePendingValidator(validatorDiff.validator)
   481  			}
   482  
   483  			addedDelegatorIterator := iterator.FromTree(validatorDiff.addedDelegators)
   484  			for addedDelegatorIterator.Next() {
   485  				baseState.PutPendingDelegator(addedDelegatorIterator.Value())
   486  			}
   487  			addedDelegatorIterator.Release()
   488  
   489  			for _, delegator := range validatorDiff.deletedDelegators {
   490  				baseState.DeletePendingDelegator(delegator)
   491  			}
   492  		}
   493  	}
   494  	for _, subnetID := range d.addedSubnetIDs {
   495  		baseState.AddSubnet(subnetID)
   496  	}
   497  	for _, tx := range d.transformedSubnets {
   498  		baseState.AddSubnetTransformation(tx)
   499  	}
   500  	for _, chains := range d.addedChains {
   501  		for _, chain := range chains {
   502  			baseState.AddChain(chain)
   503  		}
   504  	}
   505  	for _, tx := range d.addedTxs {
   506  		baseState.AddTx(tx.tx, tx.status)
   507  	}
   508  	for txID, utxos := range d.addedRewardUTXOs {
   509  		for _, utxo := range utxos {
   510  			baseState.AddRewardUTXO(txID, utxo)
   511  		}
   512  	}
   513  	for utxoID, utxo := range d.modifiedUTXOs {
   514  		if utxo != nil {
   515  			baseState.AddUTXO(utxo)
   516  		} else {
   517  			baseState.DeleteUTXO(utxoID)
   518  		}
   519  	}
   520  	for subnetID, owner := range d.subnetOwners {
   521  		baseState.SetSubnetOwner(subnetID, owner)
   522  	}
   523  	for subnetID, manager := range d.subnetManagers {
   524  		baseState.SetSubnetManager(subnetID, manager.ChainID, manager.Addr)
   525  	}
   526  	return nil
   527  }