diff --git a/api/info/service.md b/api/info/service.md index e2ee8380d0c8..9d1119ecfef5 100644 --- a/api/info/service.md +++ b/api/info/service.md @@ -512,7 +512,6 @@ info.peers({ lastReceived: string, benched: string[], observedUptime: int, - observedSubnetUptime: map[string]int, } } ``` @@ -558,7 +557,6 @@ curl -X POST --data '{ "lastReceived": "2020-06-01T15:22:57Z", "benched": [], "observedUptime": "99", - "observedSubnetUptimes": {}, "trackedSubnets": [], "benched": [] }, diff --git a/vms/example/xsvm/cmd/chain/create/cmd.go b/vms/example/xsvm/cmd/chain/create/cmd.go index a273568652f4..c6719791a05e 100644 --- a/vms/example/xsvm/cmd/chain/create/cmd.go +++ b/vms/example/xsvm/cmd/chain/create/cmd.go @@ -38,14 +38,13 @@ func createFunc(c *cobra.Command, args []string) error { ctx := c.Context() kc := secp256k1fx.NewKeychain(config.PrivateKey) - // NewWalletFromURI fetches the available UTXOs owned by [kc] on the network - // that [uri] is hosting. + // MakePWallet fetches the available UTXOs owned by [kc] on the P-chain that + // [uri] is hosting. walletSyncStartTime := time.Now() - wallet, err := primary.MakeWallet( + wallet, err := primary.MakePWallet( ctx, config.URI, kc, - kc, primary.WalletConfig{ SubnetIDs: []ids.ID{config.SubnetID}, }, @@ -55,9 +54,6 @@ func createFunc(c *cobra.Command, args []string) error { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet - pWallet := wallet.P() - genesisBytes, err := genesis.Codec.Marshal(genesis.CodecVersion, &genesis.Genesis{ Timestamp: 0, Allocations: []genesis.Allocation{ @@ -72,7 +68,7 @@ func createFunc(c *cobra.Command, args []string) error { } createChainStartTime := time.Now() - createChainTxID, err := pWallet.IssueCreateChainTx( + createChainTxID, err := wallet.IssueCreateChainTx( config.SubnetID, genesisBytes, constants.XSVMID, diff --git a/vms/platformvm/block/executor/manager.go b/vms/platformvm/block/executor/manager.go index 07560168e45c..48330dd74788 100644 --- a/vms/platformvm/block/executor/manager.go +++ b/vms/platformvm/block/executor/manager.go @@ -23,7 +23,8 @@ import ( var ( _ Manager = (*manager)(nil) - ErrChainNotSynced = errors.New("chain not synced") + ErrChainNotSynced = errors.New("chain not synced") + ErrImportTxWhilePartialSyncing = errors.New("issuing an import tx is not allowed while partial syncing") ) type Manager interface { @@ -124,6 +125,15 @@ func (m *manager) VerifyTx(tx *txs.Tx) error { return ErrChainNotSynced } + // If partial sync is enabled, this node isn't guaranteed to have the full + // UTXO set from shared memory. To avoid issuing invalid transactions, + // issuance of an ImportTx during this state is completely disallowed. + if m.txExecutorBackend.Config.PartialSyncPrimaryNetwork { + if _, isImportTx := tx.Unsigned.(*txs.ImportTx); isImportTx { + return ErrImportTxWhilePartialSyncing + } + } + recommendedPChainHeight, err := m.ctx.ValidatorState.GetMinimumHeight(context.TODO()) if err != nil { return fmt.Errorf("failed to fetch P-chain height: %w", err) diff --git a/vms/platformvm/client.go b/vms/platformvm/client.go index 86a459933dfa..31e040cfeefc 100644 --- a/vms/platformvm/client.go +++ b/vms/platformvm/client.go @@ -687,3 +687,29 @@ func GetDeactivationOwners( } return deactivationOwners, nil } + +// GetOwners returns the union of GetSubnetOwners and GetDeactivationOwners. +func GetOwners( + c Client, + ctx context.Context, + subnetIDs []ids.ID, + validationIDs []ids.ID, +) (map[ids.ID]fx.Owner, error) { + subnetOwners, err := GetSubnetOwners(c, ctx, subnetIDs...) + if err != nil { + return nil, err + } + deactivationOwners, err := GetDeactivationOwners(c, ctx, validationIDs...) + if err != nil { + return nil, err + } + + owners := make(map[ids.ID]fx.Owner, len(subnetOwners)+len(deactivationOwners)) + for id, owner := range subnetOwners { + owners[id] = owner + } + for id, owner := range deactivationOwners { + owners[id] = owner + } + return owners, nil +} diff --git a/vms/platformvm/network/network.go b/vms/platformvm/network/network.go index 45c9f4f87e99..9005dcba0aaa 100644 --- a/vms/platformvm/network/network.go +++ b/vms/platformvm/network/network.go @@ -5,7 +5,6 @@ package network import ( "context" - "errors" "sync" "time" @@ -26,8 +25,6 @@ import ( "github.com/ava-labs/avalanchego/vms/platformvm/warp" ) -var errMempoolDisabledWithPartialSync = errors.New("mempool is disabled partial syncing") - type Network struct { *p2p.Network @@ -188,18 +185,12 @@ func New( } func (n *Network) PushGossip(ctx context.Context) { - // TODO: Even though the node is running partial sync, we should support - // issuing transactions from the RPC. - if n.partialSyncPrimaryNetwork { - return - } - gossip.Every(ctx, n.log, n.txPushGossiper, n.txPushGossipFrequency) } func (n *Network) PullGossip(ctx context.Context) { - // If the node is running partial sync, we should not perform any pull - // gossip. + // If the node is running partial sync, we do not perform any pull gossip + // because we should never be a validator. if n.partialSyncPrimaryNetwork { return } @@ -219,15 +210,6 @@ func (n *Network) AppGossip(ctx context.Context, nodeID ids.NodeID, msgBytes []b } func (n *Network) IssueTxFromRPC(tx *txs.Tx) error { - // If we are partially syncing the Primary Network, we should not be - // maintaining the transaction mempool locally. - // - // TODO: We should still push the transaction to some peers when partial - // syncing. - if n.partialSyncPrimaryNetwork { - return errMempoolDisabledWithPartialSync - } - if err := n.mempool.Add(tx); err != nil { return err } diff --git a/vms/platformvm/network/network_test.go b/vms/platformvm/network/network_test.go index d7cac489f5d9..d3253a39b7c9 100644 --- a/vms/platformvm/network/network_test.go +++ b/vms/platformvm/network/network_test.go @@ -62,12 +62,11 @@ func TestNetworkIssueTxFromRPC(t *testing.T) { tx := &txs.Tx{} type test struct { - name string - mempoolFunc func(*gomock.Controller) pmempool.Mempool - txVerifier testTxVerifier - partialSyncPrimaryNetwork bool - appSenderFunc func(*gomock.Controller) common.AppSender - expectedErr error + name string + mempoolFunc func(*gomock.Controller) pmempool.Mempool + txVerifier testTxVerifier + appSenderFunc func(*gomock.Controller) common.AppSender + expectedErr error } tests := []test{ @@ -129,17 +128,6 @@ func TestNetworkIssueTxFromRPC(t *testing.T) { }, expectedErr: errTest, }, - { - name: "mempool is disabled if primary network is not being fully synced", - mempoolFunc: func(ctrl *gomock.Controller) pmempool.Mempool { - return mempoolmock.NewMempool(ctrl) - }, - partialSyncPrimaryNetwork: true, - appSenderFunc: func(ctrl *gomock.Controller) common.AppSender { - return commonmock.NewSender(ctrl) - }, - expectedErr: errMempoolDisabledWithPartialSync, - }, { name: "happy path", mempoolFunc: func(ctrl *gomock.Controller) pmempool.Mempool { @@ -174,7 +162,7 @@ func TestNetworkIssueTxFromRPC(t *testing.T) { snowCtx.ValidatorState, tt.txVerifier, tt.mempoolFunc(ctrl), - tt.partialSyncPrimaryNetwork, + false, tt.appSenderFunc(ctrl), nil, nil, diff --git a/wallet/chain/p/context.go b/wallet/chain/p/context.go index a8685e4ee0d3..73d63c3584a2 100644 --- a/wallet/chain/p/context.go +++ b/wallet/chain/p/context.go @@ -7,7 +7,7 @@ import ( "context" "github.com/ava-labs/avalanchego/api/info" - "github.com/ava-labs/avalanchego/vms/avm" + "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/vms/platformvm" "github.com/ava-labs/avalanchego/vms/platformvm/txs/fee" "github.com/ava-labs/avalanchego/wallet/chain/p/builder" @@ -21,42 +21,40 @@ const gasPriceMultiplier = 2 func NewContextFromURI(ctx context.Context, uri string) (*builder.Context, error) { infoClient := info.NewClient(uri) - xChainClient := avm.NewClient(uri, "X") - pChainClient := platformvm.NewClient(uri) - return NewContextFromClients(ctx, infoClient, xChainClient, pChainClient) + chainClient := platformvm.NewClient(uri) + return NewContextFromClients(ctx, infoClient, chainClient) } func NewContextFromClients( ctx context.Context, infoClient info.Client, - xChainClient avm.Client, - pChainClient platformvm.Client, + chainClient platformvm.Client, ) (*builder.Context, error) { networkID, err := infoClient.GetNetworkID(ctx) if err != nil { return nil, err } - asset, err := xChainClient.GetAssetDescription(ctx, "AVAX") + avaxAssetID, err := chainClient.GetStakingAssetID(ctx, constants.PrimaryNetworkID) if err != nil { return nil, err } - dynamicFeeConfig, err := pChainClient.GetFeeConfig(ctx) + dynamicFeeConfig, err := chainClient.GetFeeConfig(ctx) if err != nil { return nil, err } // TODO: After Etna is activated, assume the gas price is always non-zero. if dynamicFeeConfig.MinPrice != 0 { - _, gasPrice, _, err := pChainClient.GetFeeState(ctx) + _, gasPrice, _, err := chainClient.GetFeeState(ctx) if err != nil { return nil, err } return &builder.Context{ NetworkID: networkID, - AVAXAssetID: asset.AssetID, + AVAXAssetID: avaxAssetID, ComplexityWeights: dynamicFeeConfig.Weights, GasPrice: gasPriceMultiplier * gasPrice, }, nil @@ -69,7 +67,7 @@ func NewContextFromClients( return &builder.Context{ NetworkID: networkID, - AVAXAssetID: asset.AssetID, + AVAXAssetID: avaxAssetID, StaticFeeConfig: fee.StaticConfig{ TxFee: uint64(staticFeeConfig.TxFee), CreateSubnetTxFee: uint64(staticFeeConfig.CreateSubnetTxFee), diff --git a/wallet/subnet/primary/api.go b/wallet/subnet/primary/api.go index d9f9e5e0624a..dbf7047fafe1 100644 --- a/wallet/subnet/primary/api.go +++ b/wallet/subnet/primary/api.go @@ -80,7 +80,7 @@ func FetchState( xClient := avm.NewClient(uri, "X") cClient := evm.NewCChainClient(uri) - pCTX, err := p.NewContextFromClients(ctx, infoClient, xClient, pClient) + pCTX, err := p.NewContextFromClients(ctx, infoClient, pClient) if err != nil { return nil, err } @@ -145,6 +145,38 @@ func FetchState( }, nil } +func FetchPState( + ctx context.Context, + uri string, + addrs set.Set[ids.ShortID], +) ( + platformvm.Client, + *pbuilder.Context, + walletcommon.UTXOs, + error, +) { + infoClient := info.NewClient(uri) + chainClient := platformvm.NewClient(uri) + + context, err := p.NewContextFromClients(ctx, infoClient, chainClient) + if err != nil { + return nil, nil, nil, err + } + + utxos := walletcommon.NewUTXOs() + addrList := addrs.List() + err = AddAllUTXOs( + ctx, + utxos, + chainClient, + txs.Codec, + constants.PlatformChainID, + constants.PlatformChainID, + addrList, + ) + return chainClient, context, utxos, err +} + type EthState struct { Client ethclient.Client Accounts map[ethcommon.Address]*c.Account diff --git a/wallet/subnet/primary/examples/add-permissioned-subnet-validator/main.go b/wallet/subnet/primary/examples/add-permissioned-subnet-validator/main.go index f6f585aa6865..8e5427b28a1f 100644 --- a/wallet/subnet/primary/examples/add-permissioned-subnet-validator/main.go +++ b/wallet/subnet/primary/examples/add-permissioned-subnet-validator/main.go @@ -41,14 +41,13 @@ func main() { } log.Printf("fetched node ID %s in %s\n", nodeID, time.Since(nodeInfoStartTime)) - // MakeWallet fetches the available UTXOs owned by [kc] on the network that + // MakePWallet fetches the available UTXOs owned by [kc] on the P-chain that // [uri] is hosting and registers [subnetID]. walletSyncStartTime := time.Now() - wallet, err := primary.MakeWallet( + wallet, err := primary.MakePWallet( ctx, uri, kc, - kc, primary.WalletConfig{ SubnetIDs: []ids.ID{subnetID}, }, @@ -58,11 +57,8 @@ func main() { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet - pWallet := wallet.P() - addValidatorStartTime := time.Now() - addValidatorTx, err := pWallet.IssueAddSubnetValidatorTx(&txs.SubnetValidator{ + addValidatorTx, err := wallet.IssueAddSubnetValidatorTx(&txs.SubnetValidator{ Validator: txs.Validator{ NodeID: nodeID, Start: uint64(startTime.Unix()), diff --git a/wallet/subnet/primary/examples/add-primary-validator/main.go b/wallet/subnet/primary/examples/add-primary-validator/main.go index 21d9272b0add..9f59106cedca 100644 --- a/wallet/subnet/primary/examples/add-primary-validator/main.go +++ b/wallet/subnet/primary/examples/add-primary-validator/main.go @@ -39,14 +39,13 @@ func main() { } log.Printf("fetched node ID %s in %s\n", nodeID, time.Since(nodeInfoStartTime)) - // MakeWallet fetches the available UTXOs owned by [kc] on the network that + // MakePWallet fetches the available UTXOs owned by [kc] on the P-chain that // [uri] is hosting. walletSyncStartTime := time.Now() - wallet, err := primary.MakeWallet( + wallet, err := primary.MakePWallet( ctx, uri, kc, - kc, primary.WalletConfig{}, ) if err != nil { @@ -54,14 +53,11 @@ func main() { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet - pWallet := wallet.P() - pBuilder := pWallet.Builder() - pContext := pBuilder.Context() - avaxAssetID := pContext.AVAXAssetID + // Get the chain context + context := wallet.Builder().Context() addValidatorStartTime := time.Now() - addValidatorTx, err := pWallet.IssueAddPermissionlessValidatorTx( + addValidatorTx, err := wallet.IssueAddPermissionlessValidatorTx( &txs.SubnetValidator{Validator: txs.Validator{ NodeID: nodeID, Start: uint64(startTime.Unix()), @@ -69,7 +65,7 @@ func main() { Wght: weight, }}, nodePOP, - avaxAssetID, + context.AVAXAssetID, &secp256k1fx.OutputOwners{ Threshold: 1, Addrs: []ids.ShortID{validatorRewardAddr}, diff --git a/wallet/subnet/primary/examples/c-chain-export/main.go b/wallet/subnet/primary/examples/c-chain-export/main.go index f39ab85b496f..0967253d6262 100644 --- a/wallet/subnet/primary/examples/c-chain-export/main.go +++ b/wallet/subnet/primary/examples/c-chain-export/main.go @@ -39,7 +39,7 @@ func main() { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet + // Get the chain wallets pWallet := wallet.P() cWallet := wallet.C() diff --git a/wallet/subnet/primary/examples/c-chain-import/main.go b/wallet/subnet/primary/examples/c-chain-import/main.go index bbef83950c9e..8b599cd4b742 100644 --- a/wallet/subnet/primary/examples/c-chain-import/main.go +++ b/wallet/subnet/primary/examples/c-chain-import/main.go @@ -43,7 +43,7 @@ func main() { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet + // Get the chain wallets pWallet := wallet.P() cWallet := wallet.C() diff --git a/wallet/subnet/primary/examples/convert-subnet-to-l1/main.go b/wallet/subnet/primary/examples/convert-subnet-to-l1/main.go index cd9b02eda298..2820d5233431 100644 --- a/wallet/subnet/primary/examples/convert-subnet-to-l1/main.go +++ b/wallet/subnet/primary/examples/convert-subnet-to-l1/main.go @@ -60,14 +60,13 @@ func main() { log.Fatalf("failed to calculate conversionID: %s\n", err) } - // MakeWallet fetches the available UTXOs owned by [kc] on the network that + // MakePWallet fetches the available UTXOs owned by [kc] on the P-chain that // [uri] is hosting and registers [subnetID]. walletSyncStartTime := time.Now() - wallet, err := primary.MakeWallet( + wallet, err := primary.MakePWallet( ctx, uri, kc, - kc, primary.WalletConfig{ SubnetIDs: []ids.ID{subnetID}, }, @@ -77,11 +76,8 @@ func main() { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet - pWallet := wallet.P() - convertSubnetToL1StartTime := time.Now() - convertSubnetToL1Tx, err := pWallet.IssueConvertSubnetToL1Tx( + convertSubnetToL1Tx, err := wallet.IssueConvertSubnetToL1Tx( subnetID, chainID, address, diff --git a/wallet/subnet/primary/examples/create-chain/main.go b/wallet/subnet/primary/examples/create-chain/main.go index 215b751a560a..db83f2051a5e 100644 --- a/wallet/subnet/primary/examples/create-chain/main.go +++ b/wallet/subnet/primary/examples/create-chain/main.go @@ -47,14 +47,13 @@ func main() { ctx := context.Background() - // MakeWallet fetches the available UTXOs owned by [kc] on the network that + // MakePWallet fetches the available UTXOs owned by [kc] on the P-chain that // [uri] is hosting and registers [subnetID]. walletSyncStartTime := time.Now() - wallet, err := primary.MakeWallet( + wallet, err := primary.MakePWallet( ctx, uri, kc, - kc, primary.WalletConfig{ SubnetIDs: []ids.ID{subnetID}, }, @@ -64,11 +63,8 @@ func main() { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet - pWallet := wallet.P() - createChainStartTime := time.Now() - createChainTx, err := pWallet.IssueCreateChainTx( + createChainTx, err := wallet.IssueCreateChainTx( subnetID, genesisBytes, vmID, diff --git a/wallet/subnet/primary/examples/create-locked-stakeable/main.go b/wallet/subnet/primary/examples/create-locked-stakeable/main.go index 85496e892453..9c8ca4be35ea 100644 --- a/wallet/subnet/primary/examples/create-locked-stakeable/main.go +++ b/wallet/subnet/primary/examples/create-locked-stakeable/main.go @@ -33,14 +33,13 @@ func main() { ctx := context.Background() - // MakeWallet fetches the available UTXOs owned by [kc] on the network that + // MakePWallet fetches the available UTXOs owned by [kc] on the P-chain that // [uri] is hosting. walletSyncStartTime := time.Now() - wallet, err := primary.MakeWallet( + wallet, err := primary.MakePWallet( ctx, uri, kc, - kc, primary.WalletConfig{}, ) if err != nil { @@ -48,17 +47,14 @@ func main() { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet - pWallet := wallet.P() - pBuilder := pWallet.Builder() - pContext := pBuilder.Context() - avaxAssetID := pContext.AVAXAssetID + // Get the chain context + context := wallet.Builder().Context() issueTxStartTime := time.Now() - tx, err := pWallet.IssueBaseTx([]*avax.TransferableOutput{ + tx, err := wallet.IssueBaseTx([]*avax.TransferableOutput{ { Asset: avax.Asset{ - ID: avaxAssetID, + ID: context.AVAXAssetID, }, Out: &stakeable.LockOut{ Locktime: locktime, diff --git a/wallet/subnet/primary/examples/create-subnet/main.go b/wallet/subnet/primary/examples/create-subnet/main.go index a03023a48c37..410f50111a1e 100644 --- a/wallet/subnet/primary/examples/create-subnet/main.go +++ b/wallet/subnet/primary/examples/create-subnet/main.go @@ -22,14 +22,13 @@ func main() { ctx := context.Background() - // MakeWallet fetches the available UTXOs owned by [kc] on the network that + // MakePWallet fetches the available UTXOs owned by [kc] on the P-chain that // [uri] is hosting. walletSyncStartTime := time.Now() - wallet, err := primary.MakeWallet( + wallet, err := primary.MakePWallet( ctx, uri, kc, - kc, primary.WalletConfig{}, ) if err != nil { @@ -37,9 +36,6 @@ func main() { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet - pWallet := wallet.P() - // Pull out useful constants to use when issuing transactions. owner := &secp256k1fx.OutputOwners{ Threshold: 1, @@ -49,7 +45,7 @@ func main() { } createSubnetStartTime := time.Now() - createSubnetTx, err := pWallet.IssueCreateSubnetTx(owner) + createSubnetTx, err := wallet.IssueCreateSubnetTx(owner) if err != nil { log.Fatalf("failed to issue create subnet transaction: %s\n", err) } diff --git a/wallet/subnet/primary/examples/disable-l1-validator/main.go b/wallet/subnet/primary/examples/disable-l1-validator/main.go index af450f1b1527..990d90510aac 100644 --- a/wallet/subnet/primary/examples/disable-l1-validator/main.go +++ b/wallet/subnet/primary/examples/disable-l1-validator/main.go @@ -22,14 +22,13 @@ func main() { ctx := context.Background() - // MakeWallet fetches the available UTXOs owned by [kc] on the network that + // MakePWallet fetches the available UTXOs owned by [kc] on the P-chain that // [uri] is hosting and registers [validationID]. walletSyncStartTime := time.Now() - wallet, err := primary.MakeWallet( + wallet, err := primary.MakePWallet( ctx, uri, kc, - kc, primary.WalletConfig{ ValidationIDs: []ids.ID{validationID}, }, @@ -39,11 +38,8 @@ func main() { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet - pWallet := wallet.P() - disableL1ValidatorStartTime := time.Now() - disableL1ValidatorTx, err := pWallet.IssueDisableL1ValidatorTx( + disableL1ValidatorTx, err := wallet.IssueDisableL1ValidatorTx( validationID, ) if err != nil { diff --git a/wallet/subnet/primary/examples/increase-l1-validator-balance/main.go b/wallet/subnet/primary/examples/increase-l1-validator-balance/main.go index 79a6c49d8f16..62a6cab4a0c6 100644 --- a/wallet/subnet/primary/examples/increase-l1-validator-balance/main.go +++ b/wallet/subnet/primary/examples/increase-l1-validator-balance/main.go @@ -23,14 +23,13 @@ func main() { ctx := context.Background() - // MakeWallet fetches the available UTXOs owned by [kc] on the network that + // MakePWallet fetches the available UTXOs owned by [kc] on the P-chain that // [uri] is hosting. walletSyncStartTime := time.Now() - wallet, err := primary.MakeWallet( + wallet, err := primary.MakePWallet( ctx, uri, kc, - kc, primary.WalletConfig{}, ) if err != nil { @@ -38,11 +37,8 @@ func main() { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet - pWallet := wallet.P() - increaseL1ValidatorBalanceStartTime := time.Now() - increaseL1ValidatorBalanceTx, err := pWallet.IssueIncreaseL1ValidatorBalanceTx( + increaseL1ValidatorBalanceTx, err := wallet.IssueIncreaseL1ValidatorBalanceTx( validationID, balance, ) diff --git a/wallet/subnet/primary/examples/register-l1-validator/main.go b/wallet/subnet/primary/examples/register-l1-validator/main.go index d6d21bf826bb..f9fba80043de 100644 --- a/wallet/subnet/primary/examples/register-l1-validator/main.go +++ b/wallet/subnet/primary/examples/register-l1-validator/main.go @@ -53,14 +53,13 @@ func main() { } log.Printf("fetched node ID %s in %s\n", nodeID, time.Since(nodeInfoStartTime)) - // MakeWallet fetches the available UTXOs owned by [kc] on the network that + // MakePWallet fetches the available UTXOs owned by [kc] on the P-chain that // [uri] is hosting. walletSyncStartTime := time.Now() - wallet, err := primary.MakeWallet( + wallet, err := primary.MakePWallet( ctx, uri, kc, - kc, primary.WalletConfig{}, ) if err != nil { @@ -68,9 +67,8 @@ func main() { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet - pWallet := wallet.P() - context := pWallet.Builder().Context() + // Get the chain context + context := wallet.Builder().Context() expiry := uint64(time.Now().Add(5 * time.Minute).Unix()) // This message will expire in 5 minutes addressedCallPayload, err := message.NewRegisterL1Validator( @@ -129,7 +127,7 @@ func main() { } registerL1ValidatorStartTime := time.Now() - registerL1ValidatorTx, err := pWallet.IssueRegisterL1ValidatorTx( + registerL1ValidatorTx, err := wallet.IssueRegisterL1ValidatorTx( units.Avax, nodePoP.ProofOfPossession, warp.Bytes(), diff --git a/wallet/subnet/primary/examples/remove-subnet-validator/main.go b/wallet/subnet/primary/examples/remove-subnet-validator/main.go index e99fc717c002..0edf2bc4ab13 100644 --- a/wallet/subnet/primary/examples/remove-subnet-validator/main.go +++ b/wallet/subnet/primary/examples/remove-subnet-validator/main.go @@ -33,14 +33,13 @@ func main() { ctx := context.Background() - // MakeWallet fetches the available UTXOs owned by [kc] on the network that + // MakePWallet fetches the available UTXOs owned by [kc] on the P-chain that // [uri] is hosting and registers [subnetID]. walletSyncStartTime := time.Now() - wallet, err := primary.MakeWallet( + wallet, err := primary.MakePWallet( ctx, uri, kc, - kc, primary.WalletConfig{ SubnetIDs: []ids.ID{subnetID}, }, @@ -50,11 +49,8 @@ func main() { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet - pWallet := wallet.P() - removeValidatorStartTime := time.Now() - removeValidatorTx, err := pWallet.IssueRemoveSubnetValidatorTx( + removeValidatorTx, err := wallet.IssueRemoveSubnetValidatorTx( nodeID, subnetID, ) diff --git a/wallet/subnet/primary/examples/set-l1-validator-weight/main.go b/wallet/subnet/primary/examples/set-l1-validator-weight/main.go index 3d18440a9b52..38ade3645056 100644 --- a/wallet/subnet/primary/examples/set-l1-validator-weight/main.go +++ b/wallet/subnet/primary/examples/set-l1-validator-weight/main.go @@ -42,15 +42,14 @@ func main() { log.Fatalf("failed to parse secret key: %s\n", err) } - // MakeWallet fetches the available UTXOs owned by [kc] on the network that + // MakePWallet fetches the available UTXOs owned by [kc] on the P-chain that // [uri] is hosting. walletSyncStartTime := time.Now() ctx := context.Background() - wallet, err := primary.MakeWallet( + wallet, err := primary.MakePWallet( ctx, uri, kc, - kc, primary.WalletConfig{}, ) if err != nil { @@ -58,9 +57,8 @@ func main() { } log.Printf("synced wallet in %s\n", time.Since(walletSyncStartTime)) - // Get the P-chain wallet - pWallet := wallet.P() - context := pWallet.Builder().Context() + // Get the chain context + context := wallet.Builder().Context() addressedCallPayload, err := message.NewL1ValidatorWeight( validationID, @@ -112,7 +110,7 @@ func main() { } setWeightStartTime := time.Now() - setWeightTx, err := pWallet.IssueSetL1ValidatorWeightTx( + setWeightTx, err := wallet.IssueSetL1ValidatorWeightTx( warp.Bytes(), ) if err != nil { diff --git a/wallet/subnet/primary/wallet.go b/wallet/subnet/primary/wallet.go index fa6d49505bc8..63708ccaaad0 100644 --- a/wallet/subnet/primary/wallet.go +++ b/wallet/subnet/primary/wallet.go @@ -10,7 +10,6 @@ import ( "github.com/ava-labs/avalanchego/utils/constants" "github.com/ava-labs/avalanchego/utils/crypto/keychain" "github.com/ava-labs/avalanchego/vms/platformvm" - "github.com/ava-labs/avalanchego/vms/platformvm/fx" "github.com/ava-labs/avalanchego/wallet/chain/c" "github.com/ava-labs/avalanchego/wallet/chain/p" "github.com/ava-labs/avalanchego/wallet/chain/x" @@ -76,7 +75,7 @@ type WalletConfig struct { // that reference any of the provided keys. If the UTXOs are modified through an // external issuance process, such as another instance of the wallet, the UTXOs // may become out of sync. The wallet will also fetch all requested P-chain -// transactions. +// owners. // // The wallet manages all state locally, and performs all tx signing locally. func MakeWallet( @@ -98,23 +97,11 @@ func MakeWallet( return nil, err } - subnetOwners, err := platformvm.GetSubnetOwners(avaxState.PClient, ctx, config.SubnetIDs...) - if err != nil { - return nil, err - } - deactivationOwners, err := platformvm.GetDeactivationOwners(avaxState.PClient, ctx, config.ValidationIDs...) + owners, err := platformvm.GetOwners(avaxState.PClient, ctx, config.SubnetIDs, config.ValidationIDs) if err != nil { return nil, err } - owners := make(map[ids.ID]fx.Owner, len(subnetOwners)+len(deactivationOwners)) - for id, owner := range subnetOwners { - owners[id] = owner - } - for id, owner := range deactivationOwners { - owners[id] = owner - } - pUTXOs := common.NewChainUTXOs(constants.PlatformChainID, avaxState.UTXOs) pBackend := pwallet.NewBackend(avaxState.PCTX, pUTXOs, owners) pClient := p.NewClient(avaxState.PClient, pBackend) @@ -139,3 +126,37 @@ func MakeWallet( c.NewWallet(cBuilder, cSigner, avaxState.CClient, ethState.Client, cBackend), ), nil } + +// MakePWallet returns a P-chain wallet that supports issuing transactions. +// +// On creation, the wallet attaches to the provided uri and fetches all UTXOs +// that reference any of the provided keys. If the UTXOs are modified through an +// external issuance process, such as another instance of the wallet, the UTXOs +// may become out of sync. The wallet will also fetch all requested P-chain +// owners. +// +// The wallet manages all state locally, and performs all tx signing locally. +func MakePWallet( + ctx context.Context, + uri string, + keychain keychain.Keychain, + config WalletConfig, +) (pwallet.Wallet, error) { + addrs := keychain.Addresses() + client, context, utxos, err := FetchPState(ctx, uri, addrs) + if err != nil { + return nil, err + } + + owners, err := platformvm.GetOwners(client, ctx, config.SubnetIDs, config.ValidationIDs) + if err != nil { + return nil, err + } + + pUTXOs := common.NewChainUTXOs(constants.PlatformChainID, utxos) + pBackend := pwallet.NewBackend(context, pUTXOs, owners) + pClient := p.NewClient(client, pBackend) + pBuilder := pbuilder.New(addrs, context, pBackend) + pSigner := psigner.New(keychain, pBackend) + return pwallet.New(pClient, pBuilder, pSigner), nil +}