mirror of
https://github.com/luxfi/cli.git
synced 2026-10-30 17:01:20 +00:00
229 lines
5.9 KiB
Go
229 lines
5.9 KiB
Go
// Copyright (C) 2022, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
package vm
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
"os"
|
|
|
|
"github.com/luxfi/cli/v2/pkg/application"
|
|
"github.com/luxfi/cli/v2/pkg/constants"
|
|
"github.com/luxfi/cli/v2/pkg/models"
|
|
"github.com/luxfi/cli/v2/pkg/statemachine"
|
|
"github.com/luxfi/cli/v2/pkg/ux"
|
|
"github.com/luxfi/evm/v2/core"
|
|
"github.com/luxfi/evm/v2/params"
|
|
"github.com/luxfi/evm/v2/precompile/contracts/txallowlist"
|
|
"github.com/luxfi/geth/common"
|
|
)
|
|
|
|
func CreateEvmConfig(app *application.Lux, subnetName string, genesisPath string, evmVersion string) ([]byte, *models.Sidecar, error) {
|
|
var (
|
|
genesisBytes []byte
|
|
sc *models.Sidecar
|
|
err error
|
|
)
|
|
|
|
if genesisPath == "" {
|
|
genesisBytes, sc, err = createEvmGenesis(app, subnetName, evmVersion)
|
|
if err != nil {
|
|
return nil, &models.Sidecar{}, err
|
|
}
|
|
} else {
|
|
ux.Logger.PrintToUser("Importing genesis")
|
|
genesisBytes, err = os.ReadFile(genesisPath)
|
|
if err != nil {
|
|
return nil, &models.Sidecar{}, err
|
|
}
|
|
|
|
evmVersion, err = getVMVersion(app, "Lux EVM", constants.EVMRepoName, evmVersion, false)
|
|
if err != nil {
|
|
return nil, &models.Sidecar{}, err
|
|
}
|
|
|
|
rpcVersion, err := GetRPCProtocolVersion(app, models.EVM, evmVersion)
|
|
if err != nil {
|
|
return nil, &models.Sidecar{}, err
|
|
}
|
|
|
|
sc = &models.Sidecar{
|
|
Name: subnetName,
|
|
VM: models.EVM,
|
|
VMVersion: evmVersion,
|
|
RPCVersion: rpcVersion,
|
|
Subnet: subnetName,
|
|
TokenName: "",
|
|
}
|
|
}
|
|
|
|
return genesisBytes, sc, nil
|
|
}
|
|
|
|
func createEvmGenesis(
|
|
app *application.Lux,
|
|
subnetName string,
|
|
evmVersion string,
|
|
) ([]byte, *models.Sidecar, error) {
|
|
ux.Logger.PrintToUser("creating subnet %s", subnetName)
|
|
|
|
genesis := core.Genesis{}
|
|
conf := params.EVMDefaultChainConfig
|
|
|
|
const (
|
|
descriptorsState = "descriptors"
|
|
feeState = "fee"
|
|
airdropState = "airdrop"
|
|
precompilesState = "precompiles"
|
|
)
|
|
|
|
var (
|
|
chainID *big.Int
|
|
tokenName string
|
|
vmVersion string
|
|
allocation core.GenesisAlloc
|
|
direction statemachine.StateDirection
|
|
err error
|
|
)
|
|
|
|
subnetEvmState, err := statemachine.NewStateMachine(
|
|
[]string{descriptorsState, feeState, airdropState, precompilesState},
|
|
)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
for subnetEvmState.Running() {
|
|
switch subnetEvmState.CurrentState() {
|
|
case descriptorsState:
|
|
chainID, tokenName, vmVersion, direction, err = getDescriptors(app, evmVersion)
|
|
case feeState:
|
|
*conf, direction, err = GetFeeConfig(*conf, app)
|
|
case airdropState:
|
|
allocation, direction, err = getEVMAllocation(app)
|
|
case precompilesState:
|
|
*conf, direction, err = getPrecompiles(*conf, app)
|
|
default:
|
|
err = errors.New("invalid creation stage")
|
|
}
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
subnetEvmState.NextState(direction)
|
|
}
|
|
|
|
if conf != nil && conf.GenesisPrecompiles[txallowlist.ConfigKey] != nil {
|
|
allowListCfg, ok := conf.GenesisPrecompiles[txallowlist.ConfigKey].(*txallowlist.Config)
|
|
if !ok {
|
|
return nil, nil, fmt.Errorf("expected config of type txallowlist.AllowListConfig, but got %T", allowListCfg)
|
|
}
|
|
|
|
if err := ensureAdminsHaveBalance(
|
|
allowListCfg.AdminAddresses,
|
|
allocation); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
|
|
conf.ChainID = chainID
|
|
|
|
genesis.Alloc = allocation
|
|
genesis.Config = conf
|
|
genesis.Difficulty = Difficulty
|
|
genesis.GasLimit = conf.FeeConfig.GasLimit.Uint64()
|
|
|
|
jsonBytes, err := genesis.MarshalJSON()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
var prettyJSON bytes.Buffer
|
|
err = json.Indent(&prettyJSON, jsonBytes, "", " ")
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
rpcVersion, err := GetRPCProtocolVersion(app, models.EVM, vmVersion)
|
|
if err != nil {
|
|
return nil, &models.Sidecar{}, err
|
|
}
|
|
|
|
sc := &models.Sidecar{
|
|
Name: subnetName,
|
|
VM: models.EVM,
|
|
VMVersion: vmVersion,
|
|
RPCVersion: rpcVersion,
|
|
Subnet: subnetName,
|
|
TokenName: tokenName,
|
|
}
|
|
|
|
return prettyJSON.Bytes(), sc, nil
|
|
}
|
|
|
|
func ensureAdminsHaveBalance(admins []common.Address, alloc core.GenesisAlloc) error {
|
|
if len(admins) < 1 {
|
|
return nil
|
|
}
|
|
|
|
for _, admin := range admins {
|
|
// we can break at the first admin who has a non-zero balance
|
|
if bal, ok := alloc[admin]; ok &&
|
|
bal.Balance != nil &&
|
|
bal.Balance.Uint64() > uint64(0) {
|
|
return nil
|
|
}
|
|
}
|
|
return errors.New("none of the addresses in the transaction allow list precompile have any tokens allocated to them. Currently, no address can transact on the network. Airdrop some funds to one of the allow list addresses to continue")
|
|
}
|
|
|
|
// In own function to facilitate testing
|
|
func getEVMAllocation(app *application.Lux) (core.GenesisAlloc, statemachine.StateDirection, error) {
|
|
return getAllocation(app, defaultEvmAirdropAmount, oneLux, "Amount to airdrop (in LUX units)")
|
|
}
|
|
|
|
// CreateEVMGenesis creates a new EVM genesis configuration
|
|
func CreateEVMGenesis(chainID *big.Int, allocations core.GenesisAlloc, timestamps map[string]uint64) map[string]interface{} {
|
|
// Default configuration
|
|
config := map[string]interface{}{
|
|
"config": map[string]interface{}{
|
|
"chainId": chainID,
|
|
"homesteadBlock": 0,
|
|
"eip150Block": 0,
|
|
"eip155Block": 0,
|
|
"eip158Block": 0,
|
|
"byzantiumBlock": 0,
|
|
"constantinopleBlock": 0,
|
|
"petersburgBlock": 0,
|
|
"istanbulBlock": 0,
|
|
"muirGlacierBlock": 0,
|
|
"berlinBlock": 0,
|
|
"londonBlock": 0,
|
|
"feeConfig": map[string]interface{}{
|
|
"gasLimit": 8000000,
|
|
"targetBlockRate": 2,
|
|
"minBaseFee": 25000000000,
|
|
"targetGas": 15000000,
|
|
"baseFeeChangeDenominator": 36,
|
|
"minBlockGasCost": 0,
|
|
"maxBlockGasCost": 1000000,
|
|
"blockGasCostStep": 200000,
|
|
},
|
|
},
|
|
"alloc": allocations,
|
|
"difficulty": "0x0",
|
|
"gasLimit": "0x7A1200",
|
|
"timestamp": "0x0",
|
|
}
|
|
|
|
// Apply custom timestamps if provided
|
|
if timestamps != nil {
|
|
for key, value := range timestamps {
|
|
config[key] = fmt.Sprintf("0x%x", value)
|
|
}
|
|
}
|
|
|
|
return config
|
|
}
|