From 8fd699ca41d570599d8031aea55739f207ee1006 Mon Sep 17 00:00:00 2001 From: Raymond Sukanto Date: Tue, 21 May 2024 17:48:19 -0400 Subject: [PATCH] deploy subnet --- avalanche/app.go | 28 ++++++++++ avalanche/avalanche.go | 8 +++ avalanche/keychain.go | 18 +++++++ avalanche/network.go | 24 +++++++++ avalanche/vm.go | 29 ++++++++++ subnet/deploy_subnet.go | 116 ++++++++++++++++++++++++++++++++++++++++ subnet/subnet.go | 12 ++++- utils/common.go | 13 +++++ 8 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 avalanche/app.go create mode 100644 avalanche/avalanche.go create mode 100644 avalanche/keychain.go create mode 100644 avalanche/network.go create mode 100644 avalanche/vm.go create mode 100644 subnet/deploy_subnet.go create mode 100644 utils/common.go diff --git a/avalanche/app.go b/avalanche/app.go new file mode 100644 index 0000000..60fbb01 --- /dev/null +++ b/avalanche/app.go @@ -0,0 +1,28 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package avalanche + +import "github.com/ava-labs/avalanchego/utils/logging" + +type Avalanche struct { + Log logging.Logger + //baseDir string + //Conf *config.Config + //Prompt prompts.Prompter + //Apm *apm.APM + //ApmDir string + //Downloader Downloader +} + +func New() *Avalanche { + return &Avalanche{} +} + +func (app *Avalanche) Setup(log logging.Logger) { + //app.baseDir = baseDir + app.Log = log + //app.Conf = conf + //app.Prompt = prompt + //app.Downloader = downloader +} diff --git a/avalanche/avalanche.go b/avalanche/avalanche.go new file mode 100644 index 0000000..47770f3 --- /dev/null +++ b/avalanche/avalanche.go @@ -0,0 +1,8 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package avalanche + +const ( + SubnetEVMRepoName = "subnet-evm" +) diff --git a/avalanche/keychain.go b/avalanche/keychain.go new file mode 100644 index 0000000..fd1741c --- /dev/null +++ b/avalanche/keychain.go @@ -0,0 +1,18 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package avalanche + +import "github.com/ava-labs/avalanchego/utils/crypto/keychain" + +type Keychain struct { + Network Network + + Keychain keychain.Keychain + + Ledger keychain.Ledger + + UsesLedger bool + + LedgerIndices []uint32 +} diff --git a/avalanche/network.go b/avalanche/network.go new file mode 100644 index 0000000..fc18bea --- /dev/null +++ b/avalanche/network.go @@ -0,0 +1,24 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package avalanche + +type NetworkKind int64 + +const ( + Undefined NetworkKind = iota + Mainnet + Fuji + LocalNetwork + Devnet +) + +type Network struct { + Kind NetworkKind + + ID uint32 + + Endpoint string + + ClusterName string +} diff --git a/avalanche/vm.go b/avalanche/vm.go new file mode 100644 index 0000000..9d433b2 --- /dev/null +++ b/avalanche/vm.go @@ -0,0 +1,29 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package avalanche + +type VMType string + +const ( + SubnetEvm = "Subnet-EVM" + CustomVM = "Custom" +) + +func VMTypeFromString(s string) VMType { + switch s { + case SubnetEvm: + return SubnetEvm + default: + return CustomVM + } +} + +func (v VMType) RepoName() string { + switch v { + case SubnetEvm: + return SubnetEVMRepoName + default: + return "unknown" + } +} diff --git a/subnet/deploy_subnet.go b/subnet/deploy_subnet.go new file mode 100644 index 0000000..7bef7ef --- /dev/null +++ b/subnet/deploy_subnet.go @@ -0,0 +1,116 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package subnet + +import ( + "avalanche-tooling-sdk-go/avalanche" + "avalanche-tooling-sdk-go/utils" + "context" + "fmt" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/avalanchego/utils/crypto/keychain" + "github.com/ava-labs/avalanchego/utils/formatting/address" + "github.com/ava-labs/avalanchego/utils/set" + "github.com/ava-labs/avalanchego/vms/platformvm/txs" + "github.com/ava-labs/avalanchego/vms/secp256k1fx" + "github.com/ava-labs/avalanchego/wallet/subnet/primary" + "github.com/ava-labs/avalanchego/wallet/subnet/primary/common" +) + +// createSubnetTx creates uncommitted createSubnet transaction +func createSubnetTx(subnet Subnet, wallet primary.Wallet) (*txs.Tx, error) { + addrs, err := address.ParseToIDs(subnet.ControlKeys) + if err != nil { + return nil, fmt.Errorf("failure parsing control keys: %w", err) + } + owners := &secp256k1fx.OutputOwners{ + Addrs: addrs, + Threshold: subnet.Threshold, + Locktime: 0, + } + unsignedTx, err := wallet.P().Builder().NewCreateSubnetTx( + owners, + ) + if err != nil { + return nil, fmt.Errorf("error building tx: %w", err) + } + tx := txs.Tx{Unsigned: unsignedTx} + if err := wallet.P().Signer().Sign(context.Background(), &tx); err != nil { + return nil, fmt.Errorf("error signing tx: %w", err) + } + return &tx, nil +} + +// createBlockchainTx creates uncommitted createBlockchain transaction +func createBlockchainTx(subnet Subnet, wallet primary.Wallet, network avalanche.Network, keyChain avalanche.Keychain) (*txs.Tx, error) { + wallet, err := loadCacheWallet(network, keyChain, wallet, subnet.SubnetID, subnet.TransferSubnetOwnershipTxID) + if err != nil { + return nil, err + } + fxIDs := make([]ids.ID, 0) + options := getMultisigTxOptions(keyChain.Keychain, subnet.SubnetAuthKeys) + // create tx + unsignedTx, err := wallet.P().Builder().NewCreateChainTx( + subnet.SubnetID, + subnet.Genesis, + subnet.VMID, + fxIDs, + subnet.Name, + options..., + ) + if err != nil { + return nil, fmt.Errorf("error building tx: %w", err) + } + tx := txs.Tx{Unsigned: unsignedTx} + // sign with current wallet + if err := wallet.P().Signer().Sign(context.Background(), &tx); err != nil { + return nil, fmt.Errorf("error signing tx: %w", err) + } + return &tx, nil +} + +func getMultisigTxOptions(keychain keychain.Keychain, subnetAuthKeys []ids.ShortID) []common.Option { + options := []common.Option{} + walletAddrs := keychain.Addresses().List() + changeAddr := walletAddrs[0] + // addrs to use for signing + customAddrsSet := set.Set[ids.ShortID]{} + customAddrsSet.Add(walletAddrs...) + customAddrsSet.Add(subnetAuthKeys...) + options = append(options, common.WithCustomAddresses(customAddrsSet)) + // set change to go to wallet addr (instead of any other subnet auth key) + changeOwner := &secp256k1fx.OutputOwners{ + Threshold: 1, + Addrs: []ids.ShortID{changeAddr}, + } + options = append(options, common.WithChangeOwner(changeOwner)) + return options +} + +func loadCacheWallet(network avalanche.Network, keyChain avalanche.Keychain, wallet primary.Wallet, preloadTxs ...ids.ID) (primary.Wallet, error) { + var err error + if wallet == nil { + wallet, err = loadWallet(network, keyChain, preloadTxs...) + } + return wallet, err +} + +func loadWallet(network avalanche.Network, keyChain avalanche.Keychain, preloadTxs ...ids.ID) (primary.Wallet, error) { + ctx := context.Background() + // filter out ids.Empty txs + filteredTxs := utils.Filter(preloadTxs, func(e ids.ID) bool { return e != ids.Empty }) + wallet, err := primary.MakeWallet( + ctx, + &primary.WalletConfig{ + URI: network.Endpoint, + AVAXKeychain: keyChain.Keychain, + EthKeychain: secp256k1fx.NewKeychain(), + PChainTxsToFetch: set.Of(filteredTxs...), + }, + ) + if err != nil { + return nil, err + } + return wallet, nil +} diff --git a/subnet/subnet.go b/subnet/subnet.go index bbdba05..271687d 100644 --- a/subnet/subnet.go +++ b/subnet/subnet.go @@ -21,6 +21,8 @@ type SubnetParams struct { // Custom VM parameters to use // Do not set CustomVM value if you are using Subnet-EVM CustomVM CustomVMParams + + Name string } type SubnetEVMParams struct { @@ -86,11 +88,13 @@ type CustomVMParams struct { } type Subnet struct { + Name string + Genesis []byte ControlKeys []string - SubnetAuthKeys []string + SubnetAuthKeys []ids.ShortID SubnetID ids.ID @@ -101,4 +105,10 @@ type Subnet struct { Threshold uint32 VMID ids.ID + + RPCVersion int + + TokenName string + + TokenSymbol string } diff --git a/utils/common.go b/utils/common.go new file mode 100644 index 0000000..fbe5340 --- /dev/null +++ b/utils/common.go @@ -0,0 +1,13 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. +package utils + +func Filter[T any](input []T, f func(T) bool) []T { + output := make([]T, 0, len(input)) + for _, e := range input { + if f(e) { + output = append(output, e) + } + } + return output +}