diff --git a/README.md b/README.md index 0e9b9f841..aa86ba9b2 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,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 L1s for development and rapid prototyping - Fuji Testnet and Avalanche Mainnet deployment of L1s diff --git a/cmd/blockchaincmd/create.go b/cmd/blockchaincmd/create.go index 1c330f424..e6dbaa498 100644 --- a/cmd/blockchaincmd/create.go +++ b/cmd/blockchaincmd/create.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "os" + "os/exec" "sort" "strconv" "strings" @@ -38,6 +39,7 @@ const ( type CreateFlags struct { useSubnetEvm bool + useHyperVM bool useCustomVM bool chainID uint64 tokenSymbol string @@ -59,11 +61,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 errEmptyBlockchainName = errors.New("invalid empty name") errIllegalNameCharacter = errors.New("illegal name character: only letters, no special characters allowed") @@ -95,6 +98,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") @@ -202,7 +206,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") } @@ -221,7 +225,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 } @@ -253,7 +257,8 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { } } - if vmType == models.SubnetEvm { + switch vmType { + case models.SubnetEvm: if sovereign { // if validatorManagerOwner flag is used, we get the C Chain address of the key used if createFlags.validatorManagerOwner != "" { @@ -367,7 +372,55 @@ func createBlockchainConfig(cmd *cobra.Command, args []string) error { ); err != nil { return err } - } else { + case models.HyperVM: + if genesisPath == "" { + providePath := "I'll provide the genesis path" + binaryGen := "The VM binary will generate the genesis" + defaultGen := "Use the DefaultGenesis for my VM" + option, err := app.Prompt.CaptureList( + "How would you like to provide the genesis file?", + []string{providePath, binaryGen, defaultGen}, + ) + if err != nil { + return err + } + switch option { + 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 defaultGen: + gb, err := vm.CreateDefaultHyperSDKGenesis(app) + if err != nil { + return err + } + genesisBytes = gb + } + } + var tokenSymbol string + sc, err = vm.CreateCustomSidecar( + sc, + app, + blockchainName, + useRepo, + customVMRepoURL, + customVMBranch, + customVMBuildScript, + vmFile, + tokenSymbol, + sovereign, + ) + if err != nil { + return err + } + default: if genesisPath == "" { genesisPath, err = app.Prompt.CaptureExistingFilepath("Enter path to custom genesis") if err != nil { @@ -428,6 +481,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/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/go.mod b/go.mod index 844557daf..88314345e 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/ava-labs/avalanchego v1.12.0-initial-poc.9.0.20241125192703-8c538e65af03 github.com/ava-labs/awm-relayer v1.4.1-0.20241126163322-f9c590e20b65 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 @@ -58,6 +59,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 +145,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 +171,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,10 +215,12 @@ 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 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.27.0 // indirect golang.org/x/term v0.26.0 // indirect diff --git a/go.sum b/go.sum index 578882780..b20bf34de 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= @@ -91,6 +93,8 @@ github.com/ava-labs/awm-relayer v1.4.1-0.20241126163322-f9c590e20b65 h1:0/tUtrvR github.com/ava-labs/awm-relayer v1.4.1-0.20241126163322-f9c590e20b65/go.mod h1:gW5X5k2CspCKo+1yKVhFLriK2pl80hLjheF1521aIqs= 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= @@ -491,6 +495,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 +673,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 +707,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= @@ -848,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= @@ -914,6 +926,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 +937,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..12c3cc1fc 100644 --- a/pkg/models/sidecar.go +++ b/pkg/models/sidecar.go @@ -33,6 +33,7 @@ type Sidecar struct { Networks map[string]NetworkData ImportedFromAPM bool ImportedVMID string + CustomVMBinaryPath string CustomVMRepoURL string CustomVMBranch string CustomVMBuildScript string 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/create_custom.go b/pkg/vm/create_custom.go index a49e6a2a5..7b4b24cbf 100644 --- a/pkg/vm/create_custom.go +++ b/pkg/vm/create_custom.go @@ -61,6 +61,7 @@ func CreateCustomSidecar( if err != nil { return nil, err } + sc.CustomVMBinaryPath = vmPath } } if useRepo { diff --git a/pkg/vm/create_hypersdk.go b/pkg/vm/create_hypersdk.go new file mode 100644 index 000000000..71e5ec46c --- /dev/null +++ b/pkg/vm/create_hypersdk.go @@ -0,0 +1,206 @@ +// Copyright (C) 2024, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +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 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 { + 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())) + } + + 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(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} + + // 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 = chainID + + return json.Marshal(genesis) +} + +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 nil, err + } + switch option { + case defaultOption: + 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 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 nil, err + } + addr, err := codec.StringToAddress(addrStr) + if err != nil { + return nil, 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 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 nil, err + } + addr, err := codec.StringToAddress(addrStr) + if err != nil { + return nil, 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 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 nil, err + } + addr, err := codec.StringToAddress(addrStr) + if err != nil { + return nil, 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: + customAllocs := make([]*genesis.CustomAllocation, 0, len(balances)) + for account, bal := range balances { + customAllocs = append(customAllocs, &genesis.CustomAllocation{ + Address: account, + Balance: bal, + }) + } + return customAllocs, 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{defaultChainID, customChainID}, + ) + 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) { + 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/evm_prompts.go b/pkg/vm/evm_prompts.go index 2da6b43c3..19af6b6b8 100644 --- a/pkg/vm/evm_prompts.go +++ b/pkg/vm/evm_prompts.go @@ -103,17 +103,22 @@ func PromptTokenSymbol( func PromptVMType( app *application.Avalanche, useSubnetEvm bool, + useHyperVM bool, useCustom bool, ) (models.VMType, error) { if useSubnetEvm { return models.SubnetEvm, nil } + if useHyperVM { + return models.HyperVM, nil + } if useCustom { 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( @@ -126,6 +131,8 @@ func PromptVMType( switch option { case subnetEvmOption: subnetTypeStr = models.SubnetEvm + case hyperVMOption: + subnetTypeStr = models.HyperVM case customVMOption: subnetTypeStr = models.CustomVM case explainOption: @@ -133,6 +140,8 @@ func PromptVMType( 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 }