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 }