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 }