github.com/MetalBlockchain/metalgo@v1.11.9/wallet/chain/p/backend.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package p
     5  
     6  import (
     7  	"context"
     8  	"sync"
     9  
    10  	"github.com/MetalBlockchain/metalgo/database"
    11  	"github.com/MetalBlockchain/metalgo/ids"
    12  	"github.com/MetalBlockchain/metalgo/utils/constants"
    13  	"github.com/MetalBlockchain/metalgo/utils/set"
    14  	"github.com/MetalBlockchain/metalgo/vms/components/avax"
    15  	"github.com/MetalBlockchain/metalgo/vms/platformvm/fx"
    16  	"github.com/MetalBlockchain/metalgo/vms/platformvm/txs"
    17  	"github.com/MetalBlockchain/metalgo/wallet/chain/p/builder"
    18  	"github.com/MetalBlockchain/metalgo/wallet/chain/p/signer"
    19  	"github.com/MetalBlockchain/metalgo/wallet/subnet/primary/common"
    20  )
    21  
    22  var _ Backend = (*backend)(nil)
    23  
    24  // Backend defines the full interface required to support a P-chain wallet.
    25  type Backend interface {
    26  	builder.Backend
    27  	signer.Backend
    28  
    29  	AcceptTx(ctx context.Context, tx *txs.Tx) error
    30  }
    31  
    32  type backend struct {
    33  	common.ChainUTXOs
    34  
    35  	context *builder.Context
    36  
    37  	subnetOwnerLock sync.RWMutex
    38  	subnetOwner     map[ids.ID]fx.Owner // subnetID -> owner
    39  }
    40  
    41  func NewBackend(context *builder.Context, utxos common.ChainUTXOs, subnetTxs map[ids.ID]*txs.Tx) Backend {
    42  	subnetOwner := make(map[ids.ID]fx.Owner)
    43  	for txID, tx := range subnetTxs { // first get owners from the CreateSubnetTx
    44  		createSubnetTx, ok := tx.Unsigned.(*txs.CreateSubnetTx)
    45  		if !ok {
    46  			continue
    47  		}
    48  		subnetOwner[txID] = createSubnetTx.Owner
    49  	}
    50  	for _, tx := range subnetTxs { // then check for TransferSubnetOwnershipTx
    51  		transferSubnetOwnershipTx, ok := tx.Unsigned.(*txs.TransferSubnetOwnershipTx)
    52  		if !ok {
    53  			continue
    54  		}
    55  		subnetOwner[transferSubnetOwnershipTx.Subnet] = transferSubnetOwnershipTx.Owner
    56  	}
    57  	return &backend{
    58  		ChainUTXOs:  utxos,
    59  		context:     context,
    60  		subnetOwner: subnetOwner,
    61  	}
    62  }
    63  
    64  func (b *backend) AcceptTx(ctx context.Context, tx *txs.Tx) error {
    65  	txID := tx.ID()
    66  	err := tx.Unsigned.Visit(&backendVisitor{
    67  		b:    b,
    68  		ctx:  ctx,
    69  		txID: txID,
    70  	})
    71  	if err != nil {
    72  		return err
    73  	}
    74  
    75  	producedUTXOSlice := tx.UTXOs()
    76  	return b.addUTXOs(ctx, constants.PlatformChainID, producedUTXOSlice)
    77  }
    78  
    79  func (b *backend) addUTXOs(ctx context.Context, destinationChainID ids.ID, utxos []*avax.UTXO) error {
    80  	for _, utxo := range utxos {
    81  		if err := b.AddUTXO(ctx, destinationChainID, utxo); err != nil {
    82  			return err
    83  		}
    84  	}
    85  	return nil
    86  }
    87  
    88  func (b *backend) removeUTXOs(ctx context.Context, sourceChain ids.ID, utxoIDs set.Set[ids.ID]) error {
    89  	for utxoID := range utxoIDs {
    90  		if err := b.RemoveUTXO(ctx, sourceChain, utxoID); err != nil {
    91  			return err
    92  		}
    93  	}
    94  	return nil
    95  }
    96  
    97  func (b *backend) GetSubnetOwner(_ context.Context, subnetID ids.ID) (fx.Owner, error) {
    98  	b.subnetOwnerLock.RLock()
    99  	defer b.subnetOwnerLock.RUnlock()
   100  
   101  	owner, exists := b.subnetOwner[subnetID]
   102  	if !exists {
   103  		return nil, database.ErrNotFound
   104  	}
   105  	return owner, nil
   106  }
   107  
   108  func (b *backend) setSubnetOwner(subnetID ids.ID, owner fx.Owner) {
   109  	b.subnetOwnerLock.Lock()
   110  	defer b.subnetOwnerLock.Unlock()
   111  
   112  	b.subnetOwner[subnetID] = owner
   113  }