From 128885cde7ae88bb210dc2efe5a6e20b3e78f4c0 Mon Sep 17 00:00:00 2001 From: Rodrigo Villar Date: Wed, 20 Nov 2024 09:32:38 -0500 Subject: [PATCH 01/11] start hypersdk integration --- cmd/blockchaincmd/create.go | 41 +++++++++++++++++--- go.mod | 4 ++ go.sum | 14 +++++++ pkg/models/sidecar.go | 34 +++++++++-------- pkg/vm/create_custom.go | 42 +++++++++++++++++++++ pkg/vm/create_hypersdk_genesis.go | 62 +++++++++++++++++++++++++++++++ 6 files changed, 176 insertions(+), 21 deletions(-) create mode 100644 pkg/vm/create_hypersdk_genesis.go diff --git a/cmd/blockchaincmd/create.go b/cmd/blockchaincmd/create.go index 9f969ae4f..26804e1a4 100644 --- a/cmd/blockchaincmd/create.go +++ b/cmd/blockchaincmd/create.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "os" + "os/exec" "sort" "strconv" "strings" @@ -356,14 +357,36 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { } } else { if genesisPath == "" { - genesisPath, err = app.Prompt.CaptureExistingFilepath("Enter path to custom genesis") + providePath := "I'll provide the genesis path" + binaryGen := "The VM binary will generate the genesis" + hyperSDKOption := "HyperSDK VM Only: Use the DefaultGenesis" + options := []string{providePath, binaryGen, hyperSDKOption} + opt, err := app.Prompt.CaptureList( + "How would you like to provide the genesis file?", + options, + ) if err != nil { return err } - } - genesisBytes, err = os.ReadFile(genesisPath) - if err != nil { - return err + switch opt { + case providePath: + genesisPath, err = app.Prompt.CaptureExistingFilepath("Enter path to custom genesis") + if err != nil { + return err + } + genesisBytes, err = os.ReadFile(genesisPath) + if err != nil { + return err + } + case binaryGen: + createGenesisFromBinary = true + case hyperSDKOption: + gb, err := vm.CreateDefaultHyperSDKGenesis(app) + if err != nil { + return err + } + genesisBytes = gb + } } var tokenSymbol string if evmCompatibleGenesis := utils.ByteSliceIsSubnetEvmGenesis(genesisBytes); evmCompatibleGenesis { @@ -415,6 +438,14 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { } } + if createGenesisFromBinary { + output, err := exec.Command(sc.CustomVMBinaryPath, "genesis").Output() + if err != nil { + return err + } + genesisBytes = output + } + if err = app.WriteGenesisFile(blockchainName, genesisBytes); err != nil { return err } diff --git a/go.mod b/go.mod index 80fea607c..ae7374f46 100644 --- a/go.mod +++ b/go.mod @@ -58,6 +58,7 @@ require ( cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.5.0 // indirect dario.cat/mergo v1.0.0 // indirect + filippo.io/edwards25519 v1.0.0 // indirect github.com/DataDog/zstd v1.5.2 // indirect github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect @@ -143,6 +144,7 @@ require ( github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hdevalence/ed25519consensus v0.2.0 // indirect github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.2.4 // indirect @@ -168,6 +170,7 @@ require ( github.com/mr-tron/base58 v1.2.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect + github.com/openzipkin/zipkin-go v0.4.1 // indirect github.com/otiai10/copy v1.11.0 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pires/go-proxyproto v0.6.2 // indirect @@ -211,6 +214,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 // indirect + go.opentelemetry.io/otel/exporters/zipkin v1.11.2 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/sdk v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect diff --git a/go.sum b/go.sum index f3e5ab8bc..db78a81ac 100644 --- a/go.sum +++ b/go.sum @@ -26,6 +26,8 @@ collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= +filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= @@ -491,6 +493,8 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= +github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4= github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= @@ -667,9 +671,13 @@ github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxzi github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= +github.com/neilotoole/errgroup v0.1.6 h1:PODGqPXdT5BC/zCYIMoTrwV+ujKcW+gBXM6Ye9Ve3R8= +github.com/neilotoole/errgroup v0.1.6/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oasisprotocol/curve25519-voi v0.0.0-20230110094441-db37f07504ce h1:/pEpMk55wH0X+E5zedGEMOdLuWmV8P4+4W3+LZaM6kg= +github.com/oasisprotocol/curve25519-voi v0.0.0-20230110094441-db37f07504ce/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/okteto/remote v0.0.0-20210428052247-99de42c04148 h1:urr6T7QLPi0DFHFCJvX1JFLu8QgGRD8MFaQBv1UC7sM= github.com/okteto/remote v0.0.0-20210428052247-99de42c04148/go.mod h1:aRwo2ZLFsZWAFnIQGdk7ReXeMNk0+n0nDANPZK3Kmm8= @@ -697,6 +705,8 @@ github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7y github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A= +github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM= github.com/otiai10/copy v1.11.0 h1:OKBD80J/mLBrwnzXqGtFCzprFSGioo30JcmR4APsNwc= github.com/otiai10/copy v1.11.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww= github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks= @@ -914,6 +924,8 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 h1:H2JFg go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0/go.mod h1:WfCWp1bGoYK8MeULtI15MmQVczfR+bFkk0DF3h06QmQ= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 h1:FyjCyI9jVEfqhUh2MoSkmolPjfh5fp2hnV0b0irxH4Q= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0/go.mod h1:hYwym2nDEeZfG/motx0p7L7J1N1vyzIThemQsb4g2qY= +go.opentelemetry.io/otel/exporters/zipkin v1.11.2 h1:wGdWn04d1sEnxfO4TUF/UcQfEIu80IvqUXU1lENKyFg= +go.opentelemetry.io/otel/exporters/zipkin v1.11.2/go.mod h1:I60/FdYilVKkuDOzenyp8LqJLryRC/Mr918G5hchvkM= go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= @@ -923,6 +935,8 @@ go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= diff --git a/pkg/models/sidecar.go b/pkg/models/sidecar.go index c08676ffc..04575a280 100644 --- a/pkg/models/sidecar.go +++ b/pkg/models/sidecar.go @@ -20,22 +20,24 @@ type NetworkData struct { } type Sidecar struct { - Name string - VM VMType - VMVersion string - RPCVersion int - Subnet string - ExternalToken bool - TokenName string - TokenSymbol string - ChainID string - Version string - Networks map[string]NetworkData - ImportedFromAPM bool - ImportedVMID string - CustomVMRepoURL string - CustomVMBranch string - CustomVMBuildScript string + Name string + VM VMType + VMVersion string + RPCVersion int + Subnet string + ExternalToken bool + TokenName string + TokenSymbol string + ChainID string + Version string + Networks map[string]NetworkData + ImportedFromAPM bool + ImportedVMID string + CustomVMBinaryPath string + CustomVMRepoURL string + CustomVMBranch string + CustomVMBuildScript string + CreateGenesisFromBinary bool // Teleporter related TeleporterReady bool TeleporterKey string diff --git a/pkg/vm/create_custom.go b/pkg/vm/create_custom.go index a49e6a2a5..4d1547b40 100644 --- a/pkg/vm/create_custom.go +++ b/pkg/vm/create_custom.go @@ -14,6 +14,7 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/prompts" "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" + "github.com/ava-labs/hypersdk/codec" ) func CreateCustomSidecar( @@ -61,6 +62,7 @@ func CreateCustomSidecar( if err != nil { return nil, err } + sc.CustomVMBinaryPath = vmPath } } if useRepo { @@ -204,3 +206,43 @@ func BuildCustomVM( } return nil } + +func CreateDefaultHyperSDKGenesis(app *application.Avalanche) ([]byte, error) { + defaultOption := "I want to use defaults for a test environment" + customOption := "I don't want to use default values" + options := []string{defaultOption, customOption} + option, err := app.Prompt.CaptureList("What values do you want to use for your genesis?", options) + if err != nil { + return []byte{}, err + } + var accounts []codec.Address + switch option { + case defaultOption: + return CreateHyperSDKGenesis(nil) + case customOption: + loop: + for { + addAddressOption := "Add an address to the initial token allocation" + confirmOption := "Confirm and create genesis" + action, err := app.Prompt.CaptureList("How do you want to proceed?", []string{addAddressOption, confirmOption}) + if err != nil { + return []byte{}, err + } + switch action { + case addAddressOption: + addrStr, err := app.Prompt.CaptureString("Enter checksummed address to add to the initial token allocation") + if err != nil { + return []byte{}, err + } + addr, err := codec.StringToAddress(addrStr) + if err != nil { + return []byte{}, err + } + accounts = append(accounts, addr) + case confirmOption: + break loop + } + } + } + return CreateHyperSDKGenesis(accounts) +} diff --git a/pkg/vm/create_hypersdk_genesis.go b/pkg/vm/create_hypersdk_genesis.go new file mode 100644 index 000000000..fca2499bf --- /dev/null +++ b/pkg/vm/create_hypersdk_genesis.go @@ -0,0 +1,62 @@ +package vm + +import ( + "encoding/json" + "math" + + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/hypersdk/auth" + "github.com/ava-labs/hypersdk/codec" + "github.com/ava-labs/hypersdk/crypto/ed25519" + "github.com/ava-labs/hypersdk/fees" + "github.com/ava-labs/hypersdk/genesis" +) + +const InitialBalance uint64 = 10_000_000_000_000 + +// HyperSDK related keys +var ed25519HexKeys = []string{ + "323b1d8f4eed5f0da9da93071b034f2dce9d2d22692c172f3cb252a64ddfafd01b057de320297c29ad0c1f589ea216869cf1938d88c9fbd70d6748323dbf2fa7", //nolint:lll + "8a7be2e0c9a2d09ac2861c34326d6fe5a461d920ba9c2b345ae28e603d517df148735063f8d5d8ba79ea4668358943e5c80bc09e9b2b9a15b5b15db6c1862e88", //nolint:lll +} + +func CreateHyperSDKGenesis(accounts []codec.Address) ([]byte, error) { + if len(accounts) == 0 { + addrs := make([]codec.Address, len(ed25519HexKeys)) + testKeys := make([]ed25519.PrivateKey, len(ed25519HexKeys)) + for i, keyHex := range ed25519HexKeys { + bytes, err := codec.LoadHex(keyHex, ed25519.PrivateKeyLen) + if err != nil { + return nil, err + } + testKeys[i] = ed25519.PrivateKey(bytes) + } + for _, key := range testKeys { + addrs = append(addrs, auth.NewED25519Address(key.PublicKey())) + } + accounts = addrs + } + + customAllocs := make([]*genesis.CustomAllocation, 0, len(accounts)) + for _, account := range accounts { + customAllocs = append(customAllocs, &genesis.CustomAllocation{ + Address: account, + Balance: InitialBalance, + }) + } + + genesis := genesis.NewDefaultGenesis(customAllocs) + + // Set WindowTargetUnits to MaxUint64 for all dimensions to iterate full mempool during block building. + genesis.Rules.WindowTargetUnits = fees.Dimensions{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64} + + // Set all limits to MaxUint64 to avoid limiting block size for all dimensions except bandwidth. Must limit bandwidth to avoid building + // a block that exceeds the maximum size allowed by AvalancheGo. + genesis.Rules.MaxBlockUnits = fees.Dimensions{1800000, math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64} + genesis.Rules.MinBlockGap = 100 + + genesis.Rules.NetworkID = uint32(1) + genesis.Rules.ChainID = ids.GenerateTestID() + + return json.Marshal(genesis) +} From 275c9fd15115de33d1e365d9041dfd9a8f36c834 Mon Sep 17 00:00:00 2001 From: Rodrigo Villar Date: Wed, 20 Nov 2024 12:09:21 -0500 Subject: [PATCH 02/11] define type for hypervm --- cmd/blockchaincmd/create.go | 47 +++++++++++++++++++++++------- cmd/blockchaincmd/import_public.go | 4 ++- pkg/models/vm.go | 12 ++++---- pkg/vm/evm_prompts.go | 7 ++++- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/cmd/blockchaincmd/create.go b/cmd/blockchaincmd/create.go index 26804e1a4..ab69ebc3f 100644 --- a/cmd/blockchaincmd/create.go +++ b/cmd/blockchaincmd/create.go @@ -34,7 +34,9 @@ const ( ) type CreateFlags struct { - useSubnetEvm bool + useSubnetEvm bool + // TODO: implement all dependencies related to useHyperVM + useHyperVM bool useCustomVM bool chainID uint64 tokenSymbol string @@ -92,6 +94,7 @@ configuration, pass the -f flag.`, } cmd.Flags().StringVar(&genesisPath, "genesis", "", "file path of genesis to use") cmd.Flags().BoolVar(&createFlags.useSubnetEvm, "evm", false, "use the Subnet-EVM as the base template") + cmd.Flags().BoolVar(&createFlags.useHyperVM, "hypervm", false, "use a HyperVM as the template") cmd.Flags().BoolVar(&createFlags.useCustomVM, "custom", false, "use a custom VM template") cmd.Flags().StringVar(&createFlags.vmVersion, "vm-version", "", "version of Subnet-EVM template to use") cmd.Flags().BoolVar(&createFlags.useLatestPreReleasedVMVersion, preRelease, false, "use latest Subnet-EVM pre-released version, takes precedence over --vm-version") @@ -199,7 +202,7 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { } // vm type exclusiveness - if !flags.EnsureMutuallyExclusive([]bool{createFlags.useSubnetEvm, createFlags.useCustomVM}) { + if !flags.EnsureMutuallyExclusive([]bool{createFlags.useSubnetEvm, createFlags.useHyperVM, createFlags.useCustomVM}) { return errors.New("flags --evm,--custom are mutually exclusive") } @@ -218,7 +221,7 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { } // get vm kind - vmType, err := vm.PromptVMType(app, createFlags.useSubnetEvm, createFlags.useCustomVM) + vmType, err := vm.PromptVMType(app, createFlags.useSubnetEvm, createFlags.useHyperVM, createFlags.useCustomVM) if err != nil { return err } @@ -355,20 +358,19 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { ); err != nil { return err } - } else { + } else if vmType == models.HyperVM { if genesisPath == "" { providePath := "I'll provide the genesis path" binaryGen := "The VM binary will generate the genesis" - hyperSDKOption := "HyperSDK VM Only: Use the DefaultGenesis" - options := []string{providePath, binaryGen, hyperSDKOption} - opt, err := app.Prompt.CaptureList( + defaultGen := "Use the DefaultGenesis for my VM" + option, err := app.Prompt.CaptureList( "How would you like to provide the genesis file?", - options, + []string{providePath, binaryGen, defaultGen}, ) if err != nil { return err } - switch opt { + switch option { case providePath: genesisPath, err = app.Prompt.CaptureExistingFilepath("Enter path to custom genesis") if err != nil { @@ -380,7 +382,7 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { } case binaryGen: createGenesisFromBinary = true - case hyperSDKOption: + case defaultGen: gb, err := vm.CreateDefaultHyperSDKGenesis(app) if err != nil { return err @@ -389,6 +391,31 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { } } var tokenSymbol string + sc, err = vm.CreateCustomSidecar( + app, + blockchainName, + useRepo, + customVMRepoURL, + customVMBranch, + customVMBuildScript, + vmFile, + tokenSymbol, + ) + if err != nil { + return err + } + } else { + if genesisPath == "" { + genesisPath, err = app.Prompt.CaptureExistingFilepath("Enter path to custom genesis") + if err != nil { + return err + } + } + genesisBytes, err = os.ReadFile(genesisPath) + if err != nil { + return err + } + var tokenSymbol string if evmCompatibleGenesis := utils.ByteSliceIsSubnetEvmGenesis(genesisBytes); evmCompatibleGenesis { tokenSymbol, err = vm.PromptTokenSymbol(app, createFlags.tokenSymbol) if err != nil { diff --git a/cmd/blockchaincmd/import_public.go b/cmd/blockchaincmd/import_public.go index 6ac1e3e5a..359bd676d 100644 --- a/cmd/blockchaincmd/import_public.go +++ b/cmd/blockchaincmd/import_public.go @@ -30,6 +30,7 @@ var ( blockchainIDstr string nodeURL string useSubnetEvm bool + useHyperVM bool useCustomVM bool ) @@ -52,6 +53,7 @@ flag.`, cmd.Flags().StringVar(&nodeURL, "node-url", "", "[optional] URL of an already running subnet validator") cmd.Flags().BoolVar(&useSubnetEvm, "evm", false, "import a subnet-evm") + cmd.Flags().BoolVar(&useHyperVM, "hypervm", false, "import a hypervm") cmd.Flags().BoolVar(&useCustomVM, "custom", false, "use a custom VM template") cmd.Flags().BoolVar( &overwriteImport, @@ -140,7 +142,7 @@ func importPublic(*cobra.Command, []string) error { // TODO: it's probably possible to deploy VMs with the same name on a public network // In this case, an import could clash because the tool supports unique names only - vmType, err := vm.PromptVMType(app, useSubnetEvm, useCustomVM) + vmType, err := vm.PromptVMType(app, useSubnetEvm, useHyperVM, useCustomVM) if err != nil { return err } diff --git a/pkg/models/vm.go b/pkg/models/vm.go index 0e1342c5d..e322bec91 100644 --- a/pkg/models/vm.go +++ b/pkg/models/vm.go @@ -7,10 +7,10 @@ import "github.com/ava-labs/avalanche-cli/pkg/constants" type VMType string const ( - SubnetEvm = "Subnet-EVM" - BlobVM = "Blob VM" - TimestampVM = "Timestamp VM" - CustomVM = "Custom" + SubnetEvm = "Subnet-EVM" + BlobVM = "Blob VM" + HyperVM = "HyperVM" + CustomVM = "Custom" ) func VMTypeFromString(s string) VMType { @@ -19,8 +19,8 @@ func VMTypeFromString(s string) VMType { return SubnetEvm case BlobVM: return BlobVM - case TimestampVM: - return TimestampVM + case HyperVM: + return HyperVM default: return CustomVM } diff --git a/pkg/vm/evm_prompts.go b/pkg/vm/evm_prompts.go index 3f67e52ab..d8ccb71eb 100644 --- a/pkg/vm/evm_prompts.go +++ b/pkg/vm/evm_prompts.go @@ -102,6 +102,7 @@ func PromptTokenSymbol( func PromptVMType( app *application.Avalanche, useSubnetEvm bool, + useHyperVM bool, useCustom bool, ) (models.VMType, error) { if useSubnetEvm { @@ -111,8 +112,9 @@ func PromptVMType( return models.CustomVM, nil } subnetEvmOption := "Subnet-EVM" + hyperVMOption := "HyperVM" customVMOption := "Custom VM" - options := []string{subnetEvmOption, customVMOption, explainOption} + options := []string{subnetEvmOption, hyperVMOption, customVMOption, explainOption} var subnetTypeStr string for { option, err := app.Prompt.CaptureList( @@ -125,9 +127,12 @@ func PromptVMType( switch option { case subnetEvmOption: subnetTypeStr = models.SubnetEvm + case hyperVMOption: + subnetTypeStr = models.HyperVM case customVMOption: subnetTypeStr = models.CustomVM case explainOption: + // TODO: add explanation for HyperVM ux.Logger.PrintToUser("Virtual machines are the blueprint the defines the application-level logic of a blockchain. It determines the language and rules for writing and executing smart contracts, as well as other blockchain logic.") ux.Logger.PrintToUser("") ux.Logger.PrintToUser("Subnet-EVM is an EVM-compatible virtual machine that supports smart contract development in Solidity. This VM is an out-of-the-box solution for Blockchain deployers who want a dApp development experience that is nearly identical to Ethereum, without having to manage or create a custom virtual machine. For more information, please visit: https://github.com/ava-labs/subnet-evm") From bb627a0a584e5adcb9273b4cfe41532c744b3e13 Mon Sep 17 00:00:00 2001 From: Rodrigo Villar Date: Wed, 20 Nov 2024 12:21:35 -0500 Subject: [PATCH 03/11] clarify prealloc --- pkg/vm/create_custom.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pkg/vm/create_custom.go b/pkg/vm/create_custom.go index 4d1547b40..619e0e967 100644 --- a/pkg/vm/create_custom.go +++ b/pkg/vm/create_custom.go @@ -208,10 +208,9 @@ func BuildCustomVM( } func CreateDefaultHyperSDKGenesis(app *application.Avalanche) ([]byte, error) { - defaultOption := "I want to use defaults for a test environment" - customOption := "I don't want to use default values" - options := []string{defaultOption, customOption} - option, err := app.Prompt.CaptureList("What values do you want to use for your genesis?", options) + defaultOption := "I want to use the default preallocation list in my genesis" + customOption := "I want to define my own preallocation list" + option, err := app.Prompt.CaptureList("How would you like to define the preallocation list in your genesis?", []string{defaultOption, customOption}) if err != nil { return []byte{}, err } @@ -220,7 +219,6 @@ func CreateDefaultHyperSDKGenesis(app *application.Avalanche) ([]byte, error) { case defaultOption: return CreateHyperSDKGenesis(nil) case customOption: - loop: for { addAddressOption := "Add an address to the initial token allocation" confirmOption := "Confirm and create genesis" @@ -240,9 +238,9 @@ func CreateDefaultHyperSDKGenesis(app *application.Avalanche) ([]byte, error) { } accounts = append(accounts, addr) case confirmOption: - break loop + return CreateHyperSDKGenesis(accounts) } } } - return CreateHyperSDKGenesis(accounts) + return []byte{}, nil } From 6f1a0208bd1db47f63a3210ee0c13ac2b1c0c53f Mon Sep 17 00:00:00 2001 From: Rodrigo Villar Date: Wed, 20 Nov 2024 14:48:53 -0500 Subject: [PATCH 04/11] add explanation for hypervms --- pkg/vm/evm_prompts.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/vm/evm_prompts.go b/pkg/vm/evm_prompts.go index d8ccb71eb..1471829cb 100644 --- a/pkg/vm/evm_prompts.go +++ b/pkg/vm/evm_prompts.go @@ -132,11 +132,12 @@ func PromptVMType( case customVMOption: subnetTypeStr = models.CustomVM case explainOption: - // TODO: add explanation for HyperVM ux.Logger.PrintToUser("Virtual machines are the blueprint the defines the application-level logic of a blockchain. It determines the language and rules for writing and executing smart contracts, as well as other blockchain logic.") ux.Logger.PrintToUser("") ux.Logger.PrintToUser("Subnet-EVM is an EVM-compatible virtual machine that supports smart contract development in Solidity. This VM is an out-of-the-box solution for Blockchain deployers who want a dApp development experience that is nearly identical to Ethereum, without having to manage or create a custom virtual machine. For more information, please visit: https://github.com/ava-labs/subnet-evm") ux.Logger.PrintToUser("") + ux.Logger.PrintToUser("HyperVMs are virtual machines built with the HyperSDK. For more information, please visit: https://github.com/ava-labs/hypersdk") + ux.Logger.PrintToUser("") ux.Logger.PrintToUser("Custom VMs are virtual machines created using SDKs such as Precompile-EVM, HyperSDK, Rust-SDK. For more information please visit: https://docs.avax.network/learn/avalanche/virtual-machines.") continue } From 9d775f220f74a091f91ea86e2f03435a60f23829 Mon Sep 17 00:00:00 2001 From: Rodrigo Villar Date: Thu, 21 Nov 2024 08:32:49 -0500 Subject: [PATCH 05/11] nit --- pkg/vm/create_hypersdk_genesis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vm/create_hypersdk_genesis.go b/pkg/vm/create_hypersdk_genesis.go index fca2499bf..3b3c6e9f6 100644 --- a/pkg/vm/create_hypersdk_genesis.go +++ b/pkg/vm/create_hypersdk_genesis.go @@ -14,7 +14,7 @@ import ( const InitialBalance uint64 = 10_000_000_000_000 -// HyperSDK related keys +// Default preallocation accounts var ed25519HexKeys = []string{ "323b1d8f4eed5f0da9da93071b034f2dce9d2d22692c172f3cb252a64ddfafd01b057de320297c29ad0c1f589ea216869cf1938d88c9fbd70d6748323dbf2fa7", //nolint:lll "8a7be2e0c9a2d09ac2861c34326d6fe5a461d920ba9c2b345ae28e603d517df148735063f8d5d8ba79ea4668358943e5c80bc09e9b2b9a15b5b15db6c1862e88", //nolint:lll From 3d00b1dd440e988a8294d99ac8fc5726d5f4b68b Mon Sep 17 00:00:00 2001 From: Rodrigo Villar Date: Thu, 21 Nov 2024 09:07:18 -0500 Subject: [PATCH 06/11] improve preallocation ux --- pkg/vm/create_custom.go | 74 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 7 deletions(-) diff --git a/pkg/vm/create_custom.go b/pkg/vm/create_custom.go index 619e0e967..b73e8aaa9 100644 --- a/pkg/vm/create_custom.go +++ b/pkg/vm/create_custom.go @@ -15,6 +15,7 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" "github.com/ava-labs/hypersdk/codec" + "github.com/olekukonko/tablewriter" ) func CreateCustomSidecar( @@ -214,20 +215,21 @@ func CreateDefaultHyperSDKGenesis(app *application.Avalanche) ([]byte, error) { if err != nil { return []byte{}, err } - var accounts []codec.Address + var ( + accounts []codec.Address + ) switch option { case defaultOption: return CreateHyperSDKGenesis(nil) case customOption: + balances := make(map[codec.Address]uint64) for { - addAddressOption := "Add an address to the initial token allocation" - confirmOption := "Confirm and create genesis" - action, err := app.Prompt.CaptureList("How do you want to proceed?", []string{addAddressOption, confirmOption}) + action, err := app.Prompt.CaptureList("How do you want to proceed?", []string{addAddressAllocationOption, changeAddressAllocationOption, removeAddressAllocationOption, previewAddressAllocationOption, confirmAddressAllocationOption}) if err != nil { return []byte{}, err } switch action { - case addAddressOption: + case addAddressAllocationOption: addrStr, err := app.Prompt.CaptureString("Enter checksummed address to add to the initial token allocation") if err != nil { return []byte{}, err @@ -236,11 +238,69 @@ func CreateDefaultHyperSDKGenesis(app *application.Avalanche) ([]byte, error) { if err != nil { return []byte{}, err } - accounts = append(accounts, addr) - case confirmOption: + if _, ok := balances[addr]; ok { + ux.Logger.PrintToUser("Address already has an allocation entry. Use edit or remove to modify.") + continue + } + balance, err := app.Prompt.CaptureUint64("Enter the initial token balance for this address") + if err != nil { + return []byte{}, err + } + balances[addr] = balance + case changeAddressAllocationOption: + addrStr, err := app.Prompt.CaptureString("Enter checksummed address to edit the initial token allocation of") + if err != nil { + return []byte{}, err + } + addr, err := codec.StringToAddress(addrStr) + if err != nil { + return []byte{}, err + } + if _, ok := balances[addr]; !ok { + ux.Logger.PrintToUser("Address not found in the allocation list") + continue + } + balance, err := app.Prompt.CaptureUint64("Enter the new initial token balance for this address") + if err != nil { + return []byte{}, err + } + balances[addr] = balance + case removeAddressAllocationOption: + addrStr, err := app.Prompt.CaptureString("Enter checksummed address to remove from the initial token allocation") + if err != nil { + return []byte{}, err + } + addr, err := codec.StringToAddress(addrStr) + if err != nil { + return []byte{}, err + } + if _, ok := balances[addr]; !ok { + ux.Logger.PrintToUser("Address not found in the allocation list") + continue + } + delete(balances, addr) + case previewAddressAllocationOption: + displayHyperSDKDAllocation(balances) + case confirmAddressAllocationOption: + for addr := range balances { + accounts = append(accounts, addr) + } return CreateHyperSDKGenesis(accounts) } } } return []byte{}, nil } + +func displayHyperSDKDAllocation(allocs map[codec.Address]uint64) { + header := []string{"Address", "Balance"} + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader(header) + table.SetAutoMergeCellsByColumnIndex([]int{0}) + table.SetAutoMergeCells(true) + table.SetRowLine(true) + for addr, balance := range allocs { + table.Append([]string{addr.String(), fmt.Sprintf("%d", balance)}) + } + table.Render() +} From 6ca3d878833e0da7aba127caaa0681057d4a216e Mon Sep 17 00:00:00 2001 From: Rodrigo Villar Date: Thu, 21 Nov 2024 09:13:01 -0500 Subject: [PATCH 07/11] reorg --- pkg/vm/create_custom.go | 99 ------------------ pkg/vm/create_hypersdk.go | 164 ++++++++++++++++++++++++++++++ pkg/vm/create_hypersdk_genesis.go | 62 ----------- 3 files changed, 164 insertions(+), 161 deletions(-) create mode 100644 pkg/vm/create_hypersdk.go delete mode 100644 pkg/vm/create_hypersdk_genesis.go diff --git a/pkg/vm/create_custom.go b/pkg/vm/create_custom.go index b73e8aaa9..7b4b24cbf 100644 --- a/pkg/vm/create_custom.go +++ b/pkg/vm/create_custom.go @@ -14,8 +14,6 @@ import ( "github.com/ava-labs/avalanche-cli/pkg/prompts" "github.com/ava-labs/avalanche-cli/pkg/utils" "github.com/ava-labs/avalanche-cli/pkg/ux" - "github.com/ava-labs/hypersdk/codec" - "github.com/olekukonko/tablewriter" ) func CreateCustomSidecar( @@ -207,100 +205,3 @@ func BuildCustomVM( } return nil } - -func CreateDefaultHyperSDKGenesis(app *application.Avalanche) ([]byte, error) { - defaultOption := "I want to use the default preallocation list in my genesis" - customOption := "I want to define my own preallocation list" - option, err := app.Prompt.CaptureList("How would you like to define the preallocation list in your genesis?", []string{defaultOption, customOption}) - if err != nil { - return []byte{}, err - } - var ( - accounts []codec.Address - ) - switch option { - case defaultOption: - return CreateHyperSDKGenesis(nil) - case customOption: - balances := make(map[codec.Address]uint64) - for { - action, err := app.Prompt.CaptureList("How do you want to proceed?", []string{addAddressAllocationOption, changeAddressAllocationOption, removeAddressAllocationOption, previewAddressAllocationOption, confirmAddressAllocationOption}) - if err != nil { - return []byte{}, err - } - switch action { - case addAddressAllocationOption: - addrStr, err := app.Prompt.CaptureString("Enter checksummed address to add to the initial token allocation") - if err != nil { - return []byte{}, err - } - addr, err := codec.StringToAddress(addrStr) - if err != nil { - return []byte{}, err - } - if _, ok := balances[addr]; ok { - ux.Logger.PrintToUser("Address already has an allocation entry. Use edit or remove to modify.") - continue - } - balance, err := app.Prompt.CaptureUint64("Enter the initial token balance for this address") - if err != nil { - return []byte{}, err - } - balances[addr] = balance - case changeAddressAllocationOption: - addrStr, err := app.Prompt.CaptureString("Enter checksummed address to edit the initial token allocation of") - if err != nil { - return []byte{}, err - } - addr, err := codec.StringToAddress(addrStr) - if err != nil { - return []byte{}, err - } - if _, ok := balances[addr]; !ok { - ux.Logger.PrintToUser("Address not found in the allocation list") - continue - } - balance, err := app.Prompt.CaptureUint64("Enter the new initial token balance for this address") - if err != nil { - return []byte{}, err - } - balances[addr] = balance - case removeAddressAllocationOption: - addrStr, err := app.Prompt.CaptureString("Enter checksummed address to remove from the initial token allocation") - if err != nil { - return []byte{}, err - } - addr, err := codec.StringToAddress(addrStr) - if err != nil { - return []byte{}, err - } - if _, ok := balances[addr]; !ok { - ux.Logger.PrintToUser("Address not found in the allocation list") - continue - } - delete(balances, addr) - case previewAddressAllocationOption: - displayHyperSDKDAllocation(balances) - case confirmAddressAllocationOption: - for addr := range balances { - accounts = append(accounts, addr) - } - return CreateHyperSDKGenesis(accounts) - } - } - } - return []byte{}, nil -} - -func displayHyperSDKDAllocation(allocs map[codec.Address]uint64) { - header := []string{"Address", "Balance"} - table := tablewriter.NewWriter(os.Stdout) - table.SetHeader(header) - table.SetAutoMergeCellsByColumnIndex([]int{0}) - table.SetAutoMergeCells(true) - table.SetRowLine(true) - for addr, balance := range allocs { - table.Append([]string{addr.String(), fmt.Sprintf("%d", balance)}) - } - table.Render() -} diff --git a/pkg/vm/create_hypersdk.go b/pkg/vm/create_hypersdk.go new file mode 100644 index 000000000..d1a4b8961 --- /dev/null +++ b/pkg/vm/create_hypersdk.go @@ -0,0 +1,164 @@ +package vm + +import ( + "encoding/json" + "fmt" + "math" + "os" + + "github.com/ava-labs/avalanche-cli/pkg/application" + "github.com/ava-labs/avalanche-cli/pkg/ux" + "github.com/ava-labs/avalanchego/ids" + "github.com/ava-labs/hypersdk/auth" + "github.com/ava-labs/hypersdk/codec" + "github.com/ava-labs/hypersdk/crypto/ed25519" + "github.com/ava-labs/hypersdk/fees" + "github.com/ava-labs/hypersdk/genesis" + "github.com/olekukonko/tablewriter" +) + +const InitialBalance uint64 = 10_000_000_000_000 + +// Default preallocation accounts +var ed25519HexKeys = []string{ + "323b1d8f4eed5f0da9da93071b034f2dce9d2d22692c172f3cb252a64ddfafd01b057de320297c29ad0c1f589ea216869cf1938d88c9fbd70d6748323dbf2fa7", //nolint:lll + "8a7be2e0c9a2d09ac2861c34326d6fe5a461d920ba9c2b345ae28e603d517df148735063f8d5d8ba79ea4668358943e5c80bc09e9b2b9a15b5b15db6c1862e88", //nolint:lll +} + +func CreateHyperSDKGenesis(accounts []codec.Address) ([]byte, error) { + if len(accounts) == 0 { + addrs := make([]codec.Address, len(ed25519HexKeys)) + testKeys := make([]ed25519.PrivateKey, len(ed25519HexKeys)) + for i, keyHex := range ed25519HexKeys { + bytes, err := codec.LoadHex(keyHex, ed25519.PrivateKeyLen) + if err != nil { + return nil, err + } + testKeys[i] = ed25519.PrivateKey(bytes) + } + for _, key := range testKeys { + addrs = append(addrs, auth.NewED25519Address(key.PublicKey())) + } + accounts = addrs + } + + customAllocs := make([]*genesis.CustomAllocation, 0, len(accounts)) + for _, account := range accounts { + customAllocs = append(customAllocs, &genesis.CustomAllocation{ + Address: account, + Balance: InitialBalance, + }) + } + + genesis := genesis.NewDefaultGenesis(customAllocs) + + // Set WindowTargetUnits to MaxUint64 for all dimensions to iterate full mempool during block building. + genesis.Rules.WindowTargetUnits = fees.Dimensions{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64} + + // Set all limits to MaxUint64 to avoid limiting block size for all dimensions except bandwidth. Must limit bandwidth to avoid building + // a block that exceeds the maximum size allowed by AvalancheGo. + genesis.Rules.MaxBlockUnits = fees.Dimensions{1800000, math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64} + genesis.Rules.MinBlockGap = 100 + + genesis.Rules.NetworkID = uint32(1) + genesis.Rules.ChainID = ids.GenerateTestID() + + return json.Marshal(genesis) +} + +func CreateDefaultHyperSDKGenesis(app *application.Avalanche) ([]byte, error) { + defaultOption := "I want to use the default preallocation list in my genesis" + customOption := "I want to define my own preallocation list" + option, err := app.Prompt.CaptureList("How would you like to define the preallocation list in your genesis?", []string{defaultOption, customOption}) + if err != nil { + return []byte{}, err + } + var ( + accounts []codec.Address + ) + switch option { + case defaultOption: + return CreateHyperSDKGenesis(nil) + case customOption: + balances := make(map[codec.Address]uint64) + for { + action, err := app.Prompt.CaptureList("How do you want to proceed?", []string{addAddressAllocationOption, changeAddressAllocationOption, removeAddressAllocationOption, previewAddressAllocationOption, confirmAddressAllocationOption}) + if err != nil { + return []byte{}, err + } + switch action { + case addAddressAllocationOption: + addrStr, err := app.Prompt.CaptureString("Enter checksummed address to add to the initial token allocation") + if err != nil { + return []byte{}, err + } + addr, err := codec.StringToAddress(addrStr) + if err != nil { + return []byte{}, err + } + if _, ok := balances[addr]; ok { + ux.Logger.PrintToUser("Address already has an allocation entry. Use edit or remove to modify.") + continue + } + balance, err := app.Prompt.CaptureUint64("Enter the initial token balance for this address") + if err != nil { + return []byte{}, err + } + balances[addr] = balance + case changeAddressAllocationOption: + addrStr, err := app.Prompt.CaptureString("Enter checksummed address to edit the initial token allocation of") + if err != nil { + return []byte{}, err + } + addr, err := codec.StringToAddress(addrStr) + if err != nil { + return []byte{}, err + } + if _, ok := balances[addr]; !ok { + ux.Logger.PrintToUser("Address not found in the allocation list") + continue + } + balance, err := app.Prompt.CaptureUint64("Enter the new initial token balance for this address") + if err != nil { + return []byte{}, err + } + balances[addr] = balance + case removeAddressAllocationOption: + addrStr, err := app.Prompt.CaptureString("Enter checksummed address to remove from the initial token allocation") + if err != nil { + return []byte{}, err + } + addr, err := codec.StringToAddress(addrStr) + if err != nil { + return []byte{}, err + } + if _, ok := balances[addr]; !ok { + ux.Logger.PrintToUser("Address not found in the allocation list") + continue + } + delete(balances, addr) + case previewAddressAllocationOption: + displayHyperSDKDAllocation(balances) + case confirmAddressAllocationOption: + for addr := range balances { + accounts = append(accounts, addr) + } + return CreateHyperSDKGenesis(accounts) + } + } + } + return []byte{}, nil +} + +func displayHyperSDKDAllocation(allocs map[codec.Address]uint64) { + header := []string{"Address", "Balance"} + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader(header) + table.SetAutoMergeCellsByColumnIndex([]int{0}) + table.SetAutoMergeCells(true) + table.SetRowLine(true) + for addr, balance := range allocs { + table.Append([]string{addr.String(), fmt.Sprintf("%d", balance)}) + } + table.Render() +} diff --git a/pkg/vm/create_hypersdk_genesis.go b/pkg/vm/create_hypersdk_genesis.go deleted file mode 100644 index 3b3c6e9f6..000000000 --- a/pkg/vm/create_hypersdk_genesis.go +++ /dev/null @@ -1,62 +0,0 @@ -package vm - -import ( - "encoding/json" - "math" - - "github.com/ava-labs/avalanchego/ids" - "github.com/ava-labs/hypersdk/auth" - "github.com/ava-labs/hypersdk/codec" - "github.com/ava-labs/hypersdk/crypto/ed25519" - "github.com/ava-labs/hypersdk/fees" - "github.com/ava-labs/hypersdk/genesis" -) - -const InitialBalance uint64 = 10_000_000_000_000 - -// Default preallocation accounts -var ed25519HexKeys = []string{ - "323b1d8f4eed5f0da9da93071b034f2dce9d2d22692c172f3cb252a64ddfafd01b057de320297c29ad0c1f589ea216869cf1938d88c9fbd70d6748323dbf2fa7", //nolint:lll - "8a7be2e0c9a2d09ac2861c34326d6fe5a461d920ba9c2b345ae28e603d517df148735063f8d5d8ba79ea4668358943e5c80bc09e9b2b9a15b5b15db6c1862e88", //nolint:lll -} - -func CreateHyperSDKGenesis(accounts []codec.Address) ([]byte, error) { - if len(accounts) == 0 { - addrs := make([]codec.Address, len(ed25519HexKeys)) - testKeys := make([]ed25519.PrivateKey, len(ed25519HexKeys)) - for i, keyHex := range ed25519HexKeys { - bytes, err := codec.LoadHex(keyHex, ed25519.PrivateKeyLen) - if err != nil { - return nil, err - } - testKeys[i] = ed25519.PrivateKey(bytes) - } - for _, key := range testKeys { - addrs = append(addrs, auth.NewED25519Address(key.PublicKey())) - } - accounts = addrs - } - - customAllocs := make([]*genesis.CustomAllocation, 0, len(accounts)) - for _, account := range accounts { - customAllocs = append(customAllocs, &genesis.CustomAllocation{ - Address: account, - Balance: InitialBalance, - }) - } - - genesis := genesis.NewDefaultGenesis(customAllocs) - - // Set WindowTargetUnits to MaxUint64 for all dimensions to iterate full mempool during block building. - genesis.Rules.WindowTargetUnits = fees.Dimensions{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64} - - // Set all limits to MaxUint64 to avoid limiting block size for all dimensions except bandwidth. Must limit bandwidth to avoid building - // a block that exceeds the maximum size allowed by AvalancheGo. - genesis.Rules.MaxBlockUnits = fees.Dimensions{1800000, math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64} - genesis.Rules.MinBlockGap = 100 - - genesis.Rules.NetworkID = uint32(1) - genesis.Rules.ChainID = ids.GenerateTestID() - - return json.Marshal(genesis) -} From 08d4d43ff28c1d4f5b4a42750c6ff424deb147c8 Mon Sep 17 00:00:00 2001 From: Rodrigo Villar Date: Thu, 21 Nov 2024 09:52:05 -0500 Subject: [PATCH 08/11] refactor create_hypersdk --- pkg/vm/create_hypersdk.go | 103 ++++++++++++++++++++++++++------------ pkg/vm/evm_prompts.go | 3 ++ 2 files changed, 74 insertions(+), 32 deletions(-) diff --git a/pkg/vm/create_hypersdk.go b/pkg/vm/create_hypersdk.go index d1a4b8961..f60cd1e14 100644 --- a/pkg/vm/create_hypersdk.go +++ b/pkg/vm/create_hypersdk.go @@ -17,7 +17,9 @@ import ( "github.com/olekukonko/tablewriter" ) -const InitialBalance uint64 = 10_000_000_000_000 +const ( + InitialBalance uint64 = 10_000_000_000_000 +) // Default preallocation accounts var ed25519HexKeys = []string{ @@ -25,8 +27,20 @@ var ed25519HexKeys = []string{ "8a7be2e0c9a2d09ac2861c34326d6fe5a461d920ba9c2b345ae28e603d517df148735063f8d5d8ba79ea4668358943e5c80bc09e9b2b9a15b5b15db6c1862e88", //nolint:lll } -func CreateHyperSDKGenesis(accounts []codec.Address) ([]byte, error) { - if len(accounts) == 0 { +func CreateDefaultHyperSDKGenesis(app *application.Avalanche) ([]byte, error) { + allocs, err := getPreallocations(app) + if err != nil { + return nil, err + } + chainID, err := getChainID(app) + if err != nil { + return nil, err + } + return CreateHyperSDKGenesis(allocs, chainID) +} + +func CreateHyperSDKGenesis(allocs []*genesis.CustomAllocation, chainID ids.ID) ([]byte, error) { + if allocs == nil { addrs := make([]codec.Address, len(ed25519HexKeys)) testKeys := make([]ed25519.PrivateKey, len(ed25519HexKeys)) for i, keyHex := range ed25519HexKeys { @@ -39,18 +53,19 @@ func CreateHyperSDKGenesis(accounts []codec.Address) ([]byte, error) { for _, key := range testKeys { addrs = append(addrs, auth.NewED25519Address(key.PublicKey())) } - accounts = addrs - } - customAllocs := make([]*genesis.CustomAllocation, 0, len(accounts)) - for _, account := range accounts { - customAllocs = append(customAllocs, &genesis.CustomAllocation{ - Address: account, - Balance: InitialBalance, - }) + customAllocs := make([]*genesis.CustomAllocation, 0, len(addrs)) + for _, account := range addrs { + customAllocs = append(customAllocs, &genesis.CustomAllocation{ + Address: account, + Balance: InitialBalance, + }) + } + + allocs = customAllocs } - genesis := genesis.NewDefaultGenesis(customAllocs) + genesis := genesis.NewDefaultGenesis(allocs) // Set WindowTargetUnits to MaxUint64 for all dimensions to iterate full mempool during block building. genesis.Rules.WindowTargetUnits = fees.Dimensions{math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64, math.MaxUint64} @@ -61,40 +76,37 @@ func CreateHyperSDKGenesis(accounts []codec.Address) ([]byte, error) { genesis.Rules.MinBlockGap = 100 genesis.Rules.NetworkID = uint32(1) - genesis.Rules.ChainID = ids.GenerateTestID() + genesis.Rules.ChainID = chainID return json.Marshal(genesis) } -func CreateDefaultHyperSDKGenesis(app *application.Avalanche) ([]byte, error) { +func getPreallocations(app *application.Avalanche) ([]*genesis.CustomAllocation, error) { defaultOption := "I want to use the default preallocation list in my genesis" customOption := "I want to define my own preallocation list" option, err := app.Prompt.CaptureList("How would you like to define the preallocation list in your genesis?", []string{defaultOption, customOption}) if err != nil { - return []byte{}, err + return nil, err } - var ( - accounts []codec.Address - ) switch option { case defaultOption: - return CreateHyperSDKGenesis(nil) + return nil, nil case customOption: balances := make(map[codec.Address]uint64) for { action, err := app.Prompt.CaptureList("How do you want to proceed?", []string{addAddressAllocationOption, changeAddressAllocationOption, removeAddressAllocationOption, previewAddressAllocationOption, confirmAddressAllocationOption}) if err != nil { - return []byte{}, err + return nil, err } switch action { case addAddressAllocationOption: addrStr, err := app.Prompt.CaptureString("Enter checksummed address to add to the initial token allocation") if err != nil { - return []byte{}, err + return nil, err } addr, err := codec.StringToAddress(addrStr) if err != nil { - return []byte{}, err + return nil, err } if _, ok := balances[addr]; ok { ux.Logger.PrintToUser("Address already has an allocation entry. Use edit or remove to modify.") @@ -102,17 +114,17 @@ func CreateDefaultHyperSDKGenesis(app *application.Avalanche) ([]byte, error) { } balance, err := app.Prompt.CaptureUint64("Enter the initial token balance for this address") if err != nil { - return []byte{}, err + return nil, err } balances[addr] = balance case changeAddressAllocationOption: addrStr, err := app.Prompt.CaptureString("Enter checksummed address to edit the initial token allocation of") if err != nil { - return []byte{}, err + return nil, err } addr, err := codec.StringToAddress(addrStr) if err != nil { - return []byte{}, err + return nil, err } if _, ok := balances[addr]; !ok { ux.Logger.PrintToUser("Address not found in the allocation list") @@ -120,17 +132,17 @@ func CreateDefaultHyperSDKGenesis(app *application.Avalanche) ([]byte, error) { } balance, err := app.Prompt.CaptureUint64("Enter the new initial token balance for this address") if err != nil { - return []byte{}, err + return nil, err } balances[addr] = balance case removeAddressAllocationOption: addrStr, err := app.Prompt.CaptureString("Enter checksummed address to remove from the initial token allocation") if err != nil { - return []byte{}, err + return nil, err } addr, err := codec.StringToAddress(addrStr) if err != nil { - return []byte{}, err + return nil, err } if _, ok := balances[addr]; !ok { ux.Logger.PrintToUser("Address not found in the allocation list") @@ -140,14 +152,41 @@ func CreateDefaultHyperSDKGenesis(app *application.Avalanche) ([]byte, error) { case previewAddressAllocationOption: displayHyperSDKDAllocation(balances) case confirmAddressAllocationOption: - for addr := range balances { - accounts = append(accounts, addr) + customAllocs := make([]*genesis.CustomAllocation, 0, len(balances)) + for account, bal := range balances { + customAllocs = append(customAllocs, &genesis.CustomAllocation{ + Address: account, + Balance: bal, + }) } - return CreateHyperSDKGenesis(accounts) + return customAllocs, nil } } } - return []byte{}, nil + return nil, nil +} + +func getChainID(app *application.Avalanche) (ids.ID, error) { + customChainID := "I want to define my own chain ID" + defaultChainID := "I don't want to define my own chain ID" + chainIDOption, err := app.Prompt.CaptureList( + "How would you like to define the chain ID?", + []string{customChainID, defaultChainID}, + ) + if err != nil { + return ids.Empty, err + } + switch chainIDOption { + case customChainID: + chainID, err := app.Prompt.CaptureID("Enter the chain ID") + if err != nil { + return ids.Empty, err + } + return chainID, nil + case defaultChainID: + return ids.GenerateTestID(), nil + } + return ids.Empty, nil } func displayHyperSDKDAllocation(allocs map[codec.Address]uint64) { diff --git a/pkg/vm/evm_prompts.go b/pkg/vm/evm_prompts.go index 1471829cb..f87e728fd 100644 --- a/pkg/vm/evm_prompts.go +++ b/pkg/vm/evm_prompts.go @@ -108,6 +108,9 @@ func PromptVMType( if useSubnetEvm { return models.SubnetEvm, nil } + if useHyperVM { + return models.HyperVM, nil + } if useCustom { return models.CustomVM, nil } From 7940217d7d6e23dc62247d9eb1dab26c19100829 Mon Sep 17 00:00:00 2001 From: Rodrigo Villar Date: Thu, 21 Nov 2024 09:54:25 -0500 Subject: [PATCH 09/11] reduce diff --- pkg/models/sidecar.go | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/pkg/models/sidecar.go b/pkg/models/sidecar.go index 04575a280..12c3cc1fc 100644 --- a/pkg/models/sidecar.go +++ b/pkg/models/sidecar.go @@ -20,24 +20,23 @@ type NetworkData struct { } type Sidecar struct { - Name string - VM VMType - VMVersion string - RPCVersion int - Subnet string - ExternalToken bool - TokenName string - TokenSymbol string - ChainID string - Version string - Networks map[string]NetworkData - ImportedFromAPM bool - ImportedVMID string - CustomVMBinaryPath string - CustomVMRepoURL string - CustomVMBranch string - CustomVMBuildScript string - CreateGenesisFromBinary bool + Name string + VM VMType + VMVersion string + RPCVersion int + Subnet string + ExternalToken bool + TokenName string + TokenSymbol string + ChainID string + Version string + Networks map[string]NetworkData + ImportedFromAPM bool + ImportedVMID string + CustomVMBinaryPath string + CustomVMRepoURL string + CustomVMBranch string + CustomVMBuildScript string // Teleporter related TeleporterReady bool TeleporterKey string From b3ee33e397422c8e9386889be2c4b05b6ff2eca0 Mon Sep 17 00:00:00 2001 From: Rodrigo Villar Date: Mon, 25 Nov 2024 10:57:08 -0500 Subject: [PATCH 10/11] nit --- README.md | 3 ++- cmd/blockchaincmd/create.go | 16 +++++++++------- go.mod | 2 ++ go.sum | 6 ++++-- pkg/vm/create_hypersdk.go | 5 ++++- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 5934143d5..fcfe38697 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,8 @@ avalanche network start ## Notable Features -- Creation of Subnet-EVM, and custom virtual machine subnet configurations +- Creation of Subnet-EVM +- Creation of HyperVMs and custom virtual machine subnet configurations - Precompile integration and configuration - Local deployment of subnets for development and rapid prototyping - Fuji Testnet and Avalanche Mainnet deployment of subnets diff --git a/cmd/blockchaincmd/create.go b/cmd/blockchaincmd/create.go index ab69ebc3f..38dd4209e 100644 --- a/cmd/blockchaincmd/create.go +++ b/cmd/blockchaincmd/create.go @@ -34,8 +34,7 @@ const ( ) type CreateFlags struct { - useSubnetEvm bool - // TODO: implement all dependencies related to useHyperVM + useSubnetEvm bool useHyperVM bool useCustomVM bool chainID uint64 @@ -58,11 +57,12 @@ type CreateFlags struct { } var ( - createFlags CreateFlags - forceCreate bool - genesisPath string - vmFile string - useRepo bool + createFlags CreateFlags + createGenesisFromBinary bool + forceCreate bool + genesisPath string + vmFile string + useRepo bool errIllegalNameCharacter = errors.New( "illegal name character: only letters, no special characters allowed") @@ -392,6 +392,7 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { } var tokenSymbol string sc, err = vm.CreateCustomSidecar( + sc, app, blockchainName, useRepo, @@ -400,6 +401,7 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { customVMBuildScript, vmFile, tokenSymbol, + sovereign, ) if err != nil { return err diff --git a/go.mod b/go.mod index ae7374f46..265d88a94 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/ava-labs/avalanchego v1.12.0-fuji github.com/ava-labs/awm-relayer v1.4.1-0.20241119163059-6abfe81abee0 github.com/ava-labs/coreth v0.13.9-rc.1 + github.com/ava-labs/hypersdk v0.0.18-0.20241122232249-bb043da89f7a github.com/ava-labs/subnet-evm v0.6.12 github.com/aws/aws-sdk-go-v2 v1.32.5 github.com/aws/aws-sdk-go-v2/config v1.28.5 @@ -219,6 +220,7 @@ require ( go.opentelemetry.io/otel/sdk v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/term v0.25.0 // indirect diff --git a/go.sum b/go.sum index db78a81ac..c39ccd320 100644 --- a/go.sum +++ b/go.sum @@ -93,6 +93,8 @@ github.com/ava-labs/awm-relayer v1.4.1-0.20241119163059-6abfe81abee0 h1:/dI9oPOY github.com/ava-labs/awm-relayer v1.4.1-0.20241119163059-6abfe81abee0/go.mod h1:cLaEdx57PXwDjebIvKmY7aSGqTivAZLD0vrkXEmISvc= github.com/ava-labs/coreth v0.13.9-rc.1 h1:qIICpC/OZGYUP37QnLgIqqwGmxnLwLpZaUlqJNI85vU= github.com/ava-labs/coreth v0.13.9-rc.1/go.mod h1:7aMsRIo/3GBE44qWZMjnfqdqfcfZ5yShTTm2LObLaYo= +github.com/ava-labs/hypersdk v0.0.18-0.20241122232249-bb043da89f7a h1:QhjkEu9nmc6sP4DuvF7vcUFepS2P1NAaySGzKJ0k3WI= +github.com/ava-labs/hypersdk v0.0.18-0.20241122232249-bb043da89f7a/go.mod h1:jossurv8TsQZ6yXDHRnawOllPaVjro9S7OUSO5U149U= github.com/ava-labs/ledger-avalanche/go v0.0.0-20241009183145-e6f90a8a1a60 h1:EL66gtXOAwR/4KYBjOV03LTWgkEXvLePribLlJNu4g0= github.com/ava-labs/ledger-avalanche/go v0.0.0-20241009183145-e6f90a8a1a60/go.mod h1:/7qKobTfbzBu7eSTVaXMTr56yTYk4j2Px6/8G+idxHo= github.com/ava-labs/subnet-evm v0.6.12 h1:jL3FmjdFcNfS0qwbehwN6DkAg9y7zexB1riiGBxRsM0= @@ -858,8 +860,8 @@ github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKk github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a h1:1ur3QoCqvE5fl+nylMaIr9PVV1w343YRDtsy+Rwu7XI= github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= -github.com/thepudds/fzgen v0.4.2 h1:HlEHl5hk2/cqEomf2uK5SA/FeJc12s/vIHmOG+FbACw= -github.com/thepudds/fzgen v0.4.2/go.mod h1:kHCWdsv5tdnt32NIHYDdgq083m6bMtaY0M+ipiO9xWE= +github.com/thepudds/fzgen v0.4.3 h1:srUP/34BulQaEwPP/uHZkdjUcUjIzL7Jkf4CBVryiP8= +github.com/thepudds/fzgen v0.4.3/go.mod h1:BhhwtRhzgvLWAjjcHDJ9pEiLD2Z9hrVIFjBCHJ//zJ4= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= diff --git a/pkg/vm/create_hypersdk.go b/pkg/vm/create_hypersdk.go index f60cd1e14..71e5ec46c 100644 --- a/pkg/vm/create_hypersdk.go +++ b/pkg/vm/create_hypersdk.go @@ -1,3 +1,6 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + package vm import ( @@ -171,7 +174,7 @@ func getChainID(app *application.Avalanche) (ids.ID, error) { defaultChainID := "I don't want to define my own chain ID" chainIDOption, err := app.Prompt.CaptureList( "How would you like to define the chain ID?", - []string{customChainID, defaultChainID}, + []string{defaultChainID, customChainID}, ) if err != nil { return ids.Empty, err From cf07e090afab8243a26120eb27ad3bbbf3d87e5a Mon Sep 17 00:00:00 2001 From: Rodrigo Villar Date: Mon, 25 Nov 2024 16:12:00 -0500 Subject: [PATCH 11/11] fix lint --- cmd/blockchaincmd/create.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/blockchaincmd/create.go b/cmd/blockchaincmd/create.go index 38dd4209e..da9e22288 100644 --- a/cmd/blockchaincmd/create.go +++ b/cmd/blockchaincmd/create.go @@ -253,7 +253,8 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { } } - if vmType == models.SubnetEvm { + switch vmType { + case models.SubnetEvm: if sovereign { if createFlags.validatorManagerOwner == "" { createFlags.validatorManagerOwner, err = getValidatorContractManagerAddr() @@ -358,7 +359,7 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { ); err != nil { return err } - } else if vmType == models.HyperVM { + case models.HyperVM: if genesisPath == "" { providePath := "I'll provide the genesis path" binaryGen := "The VM binary will generate the genesis" @@ -406,7 +407,7 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { if err != nil { return err } - } else { + default: if genesisPath == "" { genesisPath, err = app.Prompt.CaptureExistingFilepath("Enter path to custom genesis") if err != nil {