2024-07-05 22:20:13 -04:00
package main
// DONTCOVER
import (
"bufio"
"encoding/json"
"fmt"
"net"
"os"
"path/filepath"
"time"
cmtconfig "github.com/cometbft/cometbft/config"
cmttime "github.com/cometbft/cometbft/types/time"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"cosmossdk.io/math"
"cosmossdk.io/math/unsafe"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/runtime"
"github.com/cosmos/cosmos-sdk/server"
srvconfig "github.com/cosmos/cosmos-sdk/server/config"
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/network"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/version"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
Feature/update dockerfile (#6)
* chore: remove unused new.Dockerfile
* feat: add DID model definitions
* fix: Fix EncodePublicKey method in KeyInfo struct
* feat: Update `EncodePublicKey` to be the inverse of `DecodePublicKey`
* refactor: update AssetInfo protobuf definition
* fix: update default assets with correct asset types
* fix: Initialize IPFS client and check for mounted directories
* feat: Improve IPFS client initialization and mount checking
* feat: Add local filesystem check for IPFS and IPNS
* fix: Use Unixfs().Get() instead of Cat() for IPFS and IPNS content retrieval
* feat: Update GetCID and GetIPNS functions to read data from IPFS node
* fix: Ensure IPFS client is initialized before pinning CID
* feat: Add AddFile and AddFolder methods
* feat: add IPFS file system abstraction
* feat: Implement IPFS file, location, and filesystem abstractions
* refactor: remove unused functions and types
* refactor: remove unused FileSystem interface
* feat: add initial wasm entrypoint
* feat: add basic vault command operations
* docs: add vault module features
* test: remove test for MsgUpdateParams
* refactor: Replace PrimaryKey with Property struct in zkprop.go
* feat: Update the `CreateWitness` and `CreateAccumulator` and `VerifyWitness` and `UpdateAccumulator` to Use the new `Accumulator` and `Witness` types. Then Clean up the code in the file and refactor the marshalling methods
* <no value>
* feat: add KeyCurve and KeyType to KeyInfo in genesis
* feat: add WASM build step to devbox.json
* feat: Add zkgate.go file
* feat: Uncomment and modify zkgate code to work with Property struct
* feat: Merge zkgate.go and zkprop.go logic
* feat: implement API endpoints for profile management
* refactor: remove unused template file
* feat(orm): remove unused ORM models
* feat: add persistent SQLite database support in WASM
* fix: Update module names in protobuf files
* feat: Add method to initialize SQLite database
* fix: update go-sqlite3 dependency to version 1.14.23
* feat: introduce database layer
* feat: Implement database layer for Vault node
* feature/update-dockerfile
* feat: Add keyshares table
* fix: Reorder the SQL statements in the tables.go file
* feat: Update the `createCredentialsTable` method to match the proper Credential struct
* feat: Update createProfilesTable and add createPropertiesTable
* feat: Add constant SQL queries to queries.go and use prepared statements in db.go
* feat: Add createKeysharesTable to internal/db/db.go
* feat: Update `createPermissionsTable` to match Permissions struct
* feat: Add database enum types
* feat: Add DIDNamespace and PermissionScope enums
* feat: Add DBConfig and DBOption types
* feat: Update the db implementation to use the provided go library
* fix: update db implementation to use go-sqlite3 v0.18.2
* fix: Refactor database connection and statement handling
* feat: Simplify db.go implementation
* feat: Convert constant SQL queries to functions in queries.go and update db.go to use prepared statements
* feat: Add models.go file with database table structs
* fix: Remove unused statement map and prepare statements
diff --git a/internal/db/db.go b/internal/db/db.go
index 201d09b..d4d4d4e 100644
--- a/internal/db/db.go
+++ b/internal/db/db.go
@@ -32,11 +32,6 @@ func Open(config *DBConfig) (*DB, error) {
Conn: conn,
}
- if err := createTables(db); err != nil {
- conn.Close()
- return nil, fmt.Errorf("failed to create tables: %w", err)
- }
-
return db, nil
}
@@ -61,114 +56,3 @@ func createTables(db *DB) error {
return nil
}
-// AddAccount adds a new account to the database
-func (db *DB) AddAccount(name, address string) error {
- return db.Exec(insertAccountQuery(name, address))
-}
-
-// AddAsset adds a new asset to the database
-func (db *DB) AddAsset(name, symbol string, decimals int, chainID int64) error {
- return db.Exec(insertAssetQuery(name, symbol, decimals, chainID))
-}
-
-// AddChain adds a new chain to the database
-func (db *DB) AddChain(name, networkID string) error {
- return db.Exec(insertChainQuery(name, networkID))
-}
-
-// AddCredential adds a new credential to the database
-func (db *DB) AddCredential(
- handle, controller, attestationType, origin string,
- credentialID, publicKey []byte,
- transport string,
- signCount uint32,
- userPresent, userVerified, backupEligible, backupState, cloneWarning bool,
-) error {
- return db.Exec(insertCredentialQuery(
- handle,
- controller,
- attestationType,
- origin,
- credentialID,
- publicKey,
- transport,
- signCount,
- userPresent,
- userVerified,
- backupEligible,
- backupState,
- cloneWarning,
- ))
-}
-
-// AddProfile adds a new profile to the database
-func (db *DB) AddProfile(
- id, subject, controller, originURI, publicMetadata, privateMetadata string,
-) error {
- return db.statements["insertProfile"].Exec(
- id, subject, controller, originURI, publicMetadata, privateMetadata,
- )
-}
-
-// AddProperty adds a new property to the database
-func (db *DB) AddProperty(
- profileID, key, accumulator, propertyKey string,
-) error {
- return db.statements["insertProperty"].Exec(
- profileID, key, accumulator, propertyKey,
- )
-}
-
-// AddPermission adds a new permission to the database
-func (db *DB) AddPermission(
- serviceID string,
- grants []DIDNamespace,
- scopes []PermissionScope,
-) error {
- grantsJSON, err := json.Marshal(grants)
- if err != nil {
- return fmt.Errorf("failed to marshal grants: %w", err)
- }
-
- scopesJSON, err := json.Marshal(scopes)
- if err != nil {
- return fmt.Errorf("failed to marshal scopes: %w", err)
- }
-
- return db.statements["insertPermission"].Exec(
- serviceID, string(grantsJSON), string(scopesJSON),
- )
-}
-
-// GetPermission retrieves the permission for the given service ID
-func (db *DB) GetPermission(serviceID string) ([]DIDNamespace, []PermissionScope, error) {
- row := db.statements["getPermission"].QueryRow(serviceID)
-
- var grantsJSON, scopesJSON string
- if err := row.Scan(&grantsJSON, &scopesJSON); err != nil {
- return nil, nil, fmt.Errorf("failed to get permission: %w", err)
- }
-
- var grants []DIDNamespace
- if err := json.Unmarshal([]byte(grantsJSON), &grants); err != nil {
- return nil, nil, fmt.Errorf("failed to unmarshal grants: %w", err)
- }
-
- var scopes []PermissionScope
- if err := json.Unmarshal([]byte(scopesJSON), &scopes); err != nil {
- return nil, nil, fmt.Errorf("failed to unmarshal scopes: %w", err)
- }
-
- return grants, scopes, nil
-}
-
-// Close closes the database connection and finalizes all prepared statements
-func (db *DB) Close() error {
- for _, stmt := range db.statements {
- stmt.Finalize()
- }
- return db.Conn.Close()
-}
diff --git a/internal/db/queries.go b/internal/db/queries.go
index 807d701..e69de29 100644
--- a/internal/db/queries.go
+++ b/internal/db/queries.go
@@ -1,79 +0,0 @@
-package db
-
-import "fmt"
-
-// Account queries
-func insertAccountQuery(name, address string) string {
- return fmt.Sprintf(`INSERT INTO accounts (name, address) VALUES (%s, %s)`, name, address)
-}
-
-// Asset queries
-func insertAssetQuery(name, symbol string, decimals int, chainID int64) string {
- return fmt.Sprintf(
- `INSERT INTO assets (name, symbol, decimals, chain_id) VALUES (%s, %s, %d, %d)`,
- name,
- symbol,
- decimals,
- chainID,
- )
-}
-
-// Chain queries
-func insertChainQuery(name string, networkID string) string {
- return fmt.Sprintf(`INSERT INTO chains (name, network_id) VALUES (%s, %d)`, name, networkID)
-}
-
-// Credential queries
-func insertCredentialQuery(
- handle, controller, attestationType, origin string,
- credentialID, publicKey []byte,
- transport string,
- signCount uint32,
- userPresent, userVerified, backupEligible, backupState, cloneWarning bool,
-) string {
- return fmt.Sprintf(`INSERT INTO credentials (
- handle, controller, attestation_type, origin,
- credential_id, public_key, transport, sign_count,
- user_present, user_verified, backup_eligible,
- backup_state, clone_warning
- ) VALUES (%s, %s, %s, %s, %s, %s, %s, %d, %t, %t, %t, %t, %t)`,
- handle, controller, attestationType, origin,
- credentialID, publicKey, transport, signCount,
- userPresent, userVerified, backupEligible,
- backupState, cloneWarning)
-}
-
-// Profile queries
-func insertProfileQuery(
- id, subject, controller, originURI, publicMetadata, privateMetadata string,
-) string {
- return fmt.Sprintf(`INSERT INTO profiles (
- id, subject, controller, origin_uri,
- public_metadata, private_metadata
- ) VALUES (%s, %s, %s, %s, %s, %s)`,
- id, subject, controller, originURI,
- publicMetadata, privateMetadata)
-}
-
-// Property queries
-func insertPropertyQuery(profileID, key, accumulator, propertyKey string) string {
- return fmt.Sprintf(`INSERT INTO properties (
- profile_id, key, accumulator, property_key
- ) VALUES (%s, %s, %s, %s)`,
- profileID, key, accumulator, propertyKey)
-}
-
-// Permission queries
-func insertPermissionQuery(serviceID, grants, scopes string) string {
- return fmt.Sprintf(
- `INSERT INTO permissions (service_id, grants, scopes) VALUES (%s, %s, %s)`,
- serviceID,
- grants,
- scopes,
- )
-}
-
-// GetPermission query
-func getPermissionQuery(serviceID string) string {
- return fmt.Sprintf(`SELECT grants, scopes FROM permissions WHERE service_id = %s`, serviceID)
-}
* fix: update Makefile to use sonrd instead of wasmd
* feat: Add targets for templ and vault in Makefile and use only make in devbox.json
* feat: add SQLite database support
* bump: version 0.6.0 → 0.7.0
* refactor: upgrade actions to latest versions
2024-09-05 01:24:57 -04:00
"github.com/onsonr/sonr/app"
2024-07-05 22:20:13 -04:00
)
var (
flagNodeDirPrefix = "node-dir-prefix"
flagNumValidators = "v"
flagOutputDir = "output-dir"
flagNodeDaemonHome = "node-daemon-home"
flagStartingIPAddress = "starting-ip-address"
flagEnableLogging = "enable-logging"
flagGRPCAddress = "grpc.address"
flagRPCAddress = "rpc.address"
flagAPIAddress = "api.address"
flagPrintMnemonic = "print-mnemonic"
// custom flags
flagCommitTimeout = "commit-timeout"
flagSingleHost = "single-host"
)
type initArgs struct {
algo string
chainID string
keyringBackend string
minGasPrices string
nodeDaemonHome string
nodeDirPrefix string
numValidators int
outputDir string
startingIPAddress string
singleMachine bool
}
type startArgs struct {
algo string
apiAddress string
chainID string
enableLogging bool
grpcAddress string
minGasPrices string
numValidators int
outputDir string
printMnemonic bool
rpcAddress string
timeoutCommit time . Duration
}
func addTestnetFlagsToCmd ( cmd * cobra . Command ) {
cmd . Flags ( ) . Int ( flagNumValidators , 4 , "Number of validators to initialize the testnet with" )
cmd . Flags ( ) . StringP ( flagOutputDir , "o" , "./.testnets" , "Directory to store initialization data for the testnet" )
cmd . Flags ( ) . String ( flags . FlagChainID , "" , "genesis file chain-id, if left blank will be randomly created" )
cmd . Flags ( ) . String ( server . FlagMinGasPrices , fmt . Sprintf ( "0.000006%s" , sdk . DefaultBondDenom ) , "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)" )
cmd . Flags ( ) . String ( flags . FlagKeyType , string ( hd . Secp256k1Type ) , "Key signing algorithm to generate keys for" )
// support old flags name for backwards compatibility
cmd . Flags ( ) . SetNormalizeFunc ( func ( f * pflag . FlagSet , name string ) pflag . NormalizedName {
if name == flags . FlagKeyAlgorithm {
name = flags . FlagKeyType
}
return pflag . NormalizedName ( name )
} )
}
// NewTestnetCmd creates a root testnet command with subcommands to run an in-process testnet or initialize
// validator configuration files for running a multi-validator testnet in a separate process
func NewTestnetCmd ( mbm module . BasicManager , genBalIterator banktypes . GenesisBalancesIterator ) * cobra . Command {
testnetCmd := & cobra . Command {
Use : "testnet" ,
Short : "subcommands for starting or configuring local testnets" ,
DisableFlagParsing : true ,
SuggestionsMinimumDistance : 2 ,
RunE : client . ValidateCmd ,
}
testnetCmd . AddCommand ( testnetStartCmd ( ) )
testnetCmd . AddCommand ( testnetInitFilesCmd ( mbm , genBalIterator ) )
return testnetCmd
}
// testnetInitFilesCmd returns a cmd to initialize all files for CometBFT testnet and application
func testnetInitFilesCmd ( mbm module . BasicManager , genBalIterator banktypes . GenesisBalancesIterator ) * cobra . Command {
cmd := & cobra . Command {
Use : "init-files" ,
Short : "Initialize config directories & files for a multi-validator testnet running locally via separate processes (e.g. Docker Compose or similar)" ,
Long : fmt . Sprintf ( ` init - files will setup "v" number of directories and populate each with
necessary files ( private validator , genesis , config , etc . ) for running "v" validator nodes .
Booting up a network with these validator folders is intended to be used with Docker Compose ,
or a similar setup where each node has a manually configurable IP address .
Note , strict routability for addresses is turned off in the config file .
Example :
% s testnet init - files -- v 4 -- output - dir . / . testnets -- starting - ip - address 192.168 .10 .2
` , version . AppName ) ,
RunE : func ( cmd * cobra . Command , _ [ ] string ) error {
clientCtx , err := client . GetClientQueryContext ( cmd )
if err != nil {
return err
}
serverCtx := server . GetServerContextFromCmd ( cmd )
config := serverCtx . Config
args := initArgs { }
args . outputDir , _ = cmd . Flags ( ) . GetString ( flagOutputDir )
args . keyringBackend , _ = cmd . Flags ( ) . GetString ( flags . FlagKeyringBackend )
args . chainID , _ = cmd . Flags ( ) . GetString ( flags . FlagChainID )
args . minGasPrices , _ = cmd . Flags ( ) . GetString ( server . FlagMinGasPrices )
args . nodeDirPrefix , _ = cmd . Flags ( ) . GetString ( flagNodeDirPrefix )
args . nodeDaemonHome , _ = cmd . Flags ( ) . GetString ( flagNodeDaemonHome )
args . startingIPAddress , _ = cmd . Flags ( ) . GetString ( flagStartingIPAddress )
args . numValidators , _ = cmd . Flags ( ) . GetInt ( flagNumValidators )
args . algo , _ = cmd . Flags ( ) . GetString ( flags . FlagKeyType )
args . singleMachine , _ = cmd . Flags ( ) . GetBool ( flagSingleHost )
config . Consensus . TimeoutCommit , err = cmd . Flags ( ) . GetDuration ( flagCommitTimeout )
if err != nil {
return err
}
return initTestnetFiles ( clientCtx , cmd , config , mbm , genBalIterator , clientCtx . TxConfig . SigningContext ( ) . ValidatorAddressCodec ( ) , args )
} ,
}
addTestnetFlagsToCmd ( cmd )
cmd . Flags ( ) . String ( flagNodeDirPrefix , "node" , "Prefix the directory name for each node with (node results in node0, node1, ...)" )
cmd . Flags ( ) . String ( flagNodeDaemonHome , version . AppName , "Home directory of the node's daemon configuration" )
cmd . Flags ( ) . String ( flagStartingIPAddress , "192.168.0.1" , "Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)" )
cmd . Flags ( ) . String ( flags . FlagKeyringBackend , flags . DefaultKeyringBackend , "Select keyring's backend (os|file|test)" )
cmd . Flags ( ) . Duration ( flagCommitTimeout , 5 * time . Second , "Time to wait after a block commit before starting on the new height" )
cmd . Flags ( ) . Bool ( flagSingleHost , false , "Cluster runs on a single host machine with different ports" )
return cmd
}
// testnetStartCmd returns a cmd to start multi validator in-process testnet
func testnetStartCmd ( ) * cobra . Command {
cmd := & cobra . Command {
Use : "start" ,
Short : "Launch an in-process multi-validator testnet" ,
Long : fmt . Sprintf ( ` testnet will launch an in - process multi - validator testnet ,
and generate "v" directories , populated with necessary validator configuration files
( private validator , genesis , config , etc . ) .
Example :
% s testnet -- v 4 -- output - dir . / . testnets
` , version . AppName ) ,
RunE : func ( cmd * cobra . Command , _ [ ] string ) error {
args := startArgs { }
args . outputDir , _ = cmd . Flags ( ) . GetString ( flagOutputDir )
args . chainID , _ = cmd . Flags ( ) . GetString ( flags . FlagChainID )
args . minGasPrices , _ = cmd . Flags ( ) . GetString ( server . FlagMinGasPrices )
args . numValidators , _ = cmd . Flags ( ) . GetInt ( flagNumValidators )
args . algo , _ = cmd . Flags ( ) . GetString ( flags . FlagKeyType )
args . enableLogging , _ = cmd . Flags ( ) . GetBool ( flagEnableLogging )
args . rpcAddress , _ = cmd . Flags ( ) . GetString ( flagRPCAddress )
args . apiAddress , _ = cmd . Flags ( ) . GetString ( flagAPIAddress )
args . grpcAddress , _ = cmd . Flags ( ) . GetString ( flagGRPCAddress )
args . printMnemonic , _ = cmd . Flags ( ) . GetBool ( flagPrintMnemonic )
return startTestnet ( cmd , args )
} ,
}
addTestnetFlagsToCmd ( cmd )
cmd . Flags ( ) . Bool ( flagEnableLogging , false , "Enable INFO logging of CometBFT validator nodes" )
cmd . Flags ( ) . String ( flagRPCAddress , "tcp://0.0.0.0:26657" , "the RPC address to listen on" )
cmd . Flags ( ) . String ( flagAPIAddress , "tcp://0.0.0.0:1317" , "the address to listen on for REST API" )
cmd . Flags ( ) . String ( flagGRPCAddress , "0.0.0.0:9090" , "the gRPC server address to listen on" )
cmd . Flags ( ) . Bool ( flagPrintMnemonic , true , "print mnemonic of first validator to stdout for manual testing" )
return cmd
}
const nodeDirPerm = 0 o755
// initTestnetFiles initializes testnet files for a testnet to be run in a separate process
func initTestnetFiles (
clientCtx client . Context ,
cmd * cobra . Command ,
nodeConfig * cmtconfig . Config ,
mbm module . BasicManager ,
genBalIterator banktypes . GenesisBalancesIterator ,
valAddrCodec runtime . ValidatorAddressCodec ,
args initArgs ,
) error {
if args . chainID == "" {
args . chainID = "chain-" + unsafe . Str ( 6 )
}
nodeIDs := make ( [ ] string , args . numValidators )
valPubKeys := make ( [ ] cryptotypes . PubKey , args . numValidators )
appConfig := srvconfig . DefaultConfig ( )
appConfig . MinGasPrices = args . minGasPrices
appConfig . API . Enable = true
appConfig . Telemetry . Enabled = true
appConfig . Telemetry . PrometheusRetentionTime = 60
appConfig . Telemetry . EnableHostnameLabel = false
appConfig . Telemetry . GlobalLabels = [ ] [ ] string { { "chain_id" , args . chainID } }
var (
genAccounts [ ] authtypes . GenesisAccount
genBalances [ ] banktypes . Balance
genFiles [ ] string
)
const (
rpcPort = 26657
apiPort = 1317
grpcPort = 9090
)
p2pPortStart := 26656
inBuf := bufio . NewReader ( cmd . InOrStdin ( ) )
// generate private keys, node IDs, and initial transactions
for i := 0 ; i < args . numValidators ; i ++ {
var portOffset int
if args . singleMachine {
portOffset = i
p2pPortStart = 16656 // use different start point to not conflict with rpc port
nodeConfig . P2P . AddrBookStrict = false
nodeConfig . P2P . PexReactor = false
nodeConfig . P2P . AllowDuplicateIP = true
}
nodeDirName := fmt . Sprintf ( "%s%d" , args . nodeDirPrefix , i )
nodeDir := filepath . Join ( args . outputDir , nodeDirName , args . nodeDaemonHome )
gentxsDir := filepath . Join ( args . outputDir , "gentxs" )
nodeConfig . SetRoot ( nodeDir )
nodeConfig . Moniker = nodeDirName
nodeConfig . RPC . ListenAddress = "tcp://0.0.0.0:26657"
appConfig . API . Address = fmt . Sprintf ( "tcp://0.0.0.0:%d" , apiPort + portOffset )
appConfig . GRPC . Address = fmt . Sprintf ( "0.0.0.0:%d" , grpcPort + portOffset )
appConfig . GRPCWeb . Enable = true
if err := os . MkdirAll ( filepath . Join ( nodeDir , "config" ) , nodeDirPerm ) ; err != nil {
_ = os . RemoveAll ( args . outputDir )
return err
}
ip , err := getIP ( i , args . startingIPAddress )
if err != nil {
_ = os . RemoveAll ( args . outputDir )
return err
}
nodeIDs [ i ] , valPubKeys [ i ] , err = genutil . InitializeNodeValidatorFiles ( nodeConfig )
if err != nil {
_ = os . RemoveAll ( args . outputDir )
return err
}
memo := fmt . Sprintf ( "%s@%s:%d" , nodeIDs [ i ] , ip , p2pPortStart + portOffset )
genFiles = append ( genFiles , nodeConfig . GenesisFile ( ) )
kb , err := keyring . New ( sdk . KeyringServiceName ( ) , args . keyringBackend , nodeDir , inBuf , clientCtx . Codec )
if err != nil {
return err
}
keyringAlgos , _ := kb . SupportedAlgorithms ( )
algo , err := keyring . NewSigningAlgoFromString ( args . algo , keyringAlgos )
if err != nil {
return err
}
addr , secret , err := testutil . GenerateSaveCoinKey ( kb , nodeDirName , "" , true , algo )
if err != nil {
_ = os . RemoveAll ( args . outputDir )
return err
}
info := map [ string ] string { "secret" : secret }
cliPrint , err := json . Marshal ( info )
if err != nil {
return err
}
// save private key seed words
if err := writeFile ( fmt . Sprintf ( "%v.json" , "key_seed" ) , nodeDir , cliPrint ) ; err != nil {
return err
}
accTokens := sdk . TokensFromConsensusPower ( 1000 , sdk . DefaultPowerReduction )
accStakingTokens := sdk . TokensFromConsensusPower ( 500 , sdk . DefaultPowerReduction )
coins := sdk . Coins {
sdk . NewCoin ( "testtoken" , accTokens ) ,
sdk . NewCoin ( sdk . DefaultBondDenom , accStakingTokens ) ,
}
genBalances = append ( genBalances , banktypes . Balance { Address : addr . String ( ) , Coins : coins . Sort ( ) } )
genAccounts = append ( genAccounts , authtypes . NewBaseAccount ( addr , nil , 0 , 0 ) )
valStr , err := valAddrCodec . BytesToString ( sdk . ValAddress ( addr ) )
if err != nil {
return err
}
valTokens := sdk . TokensFromConsensusPower ( 100 , sdk . DefaultPowerReduction )
createValMsg , err := stakingtypes . NewMsgCreateValidator (
valStr ,
valPubKeys [ i ] ,
sdk . NewCoin ( sdk . DefaultBondDenom , valTokens ) ,
stakingtypes . NewDescription ( nodeDirName , "" , "" , "" , "" ) ,
stakingtypes . NewCommissionRates ( math . LegacyOneDec ( ) , math . LegacyOneDec ( ) , math . LegacyOneDec ( ) ) ,
math . OneInt ( ) ,
)
if err != nil {
return err
}
txBuilder := clientCtx . TxConfig . NewTxBuilder ( )
if err := txBuilder . SetMsgs ( createValMsg ) ; err != nil {
return err
}
txBuilder . SetMemo ( memo )
txFactory := tx . Factory { }
txFactory = txFactory .
WithChainID ( args . chainID ) .
WithMemo ( memo ) .
WithKeybase ( kb ) .
WithTxConfig ( clientCtx . TxConfig )
if err := tx . Sign ( cmd . Context ( ) , txFactory , nodeDirName , txBuilder , true ) ; err != nil {
return err
}
txBz , err := clientCtx . TxConfig . TxJSONEncoder ( ) ( txBuilder . GetTx ( ) )
if err != nil {
return err
}
if err := writeFile ( fmt . Sprintf ( "%v.json" , nodeDirName ) , gentxsDir , txBz ) ; err != nil {
return err
}
srvconfig . SetConfigTemplate ( srvconfig . DefaultConfigTemplate )
srvconfig . WriteConfigFile ( filepath . Join ( nodeDir , "config" , "app.toml" ) , appConfig )
}
if err := initGenFiles ( clientCtx , mbm , args . chainID , genAccounts , genBalances , genFiles , args . numValidators ) ; err != nil {
return err
}
err := collectGenFiles (
clientCtx , nodeConfig , args . chainID , nodeIDs , valPubKeys , args . numValidators ,
args . outputDir , args . nodeDirPrefix , args . nodeDaemonHome , genBalIterator , valAddrCodec ,
rpcPort , p2pPortStart , args . singleMachine ,
)
if err != nil {
return err
}
cmd . PrintErrf ( "Successfully initialized %d node directories\n" , args . numValidators )
return nil
}
func initGenFiles (
clientCtx client . Context , mbm module . BasicManager , chainID string ,
genAccounts [ ] authtypes . GenesisAccount , genBalances [ ] banktypes . Balance ,
genFiles [ ] string , numValidators int ,
) error {
appGenState := mbm . DefaultGenesis ( clientCtx . Codec )
// set the accounts in the genesis state
var authGenState authtypes . GenesisState
clientCtx . Codec . MustUnmarshalJSON ( appGenState [ authtypes . ModuleName ] , & authGenState )
accounts , err := authtypes . PackAccounts ( genAccounts )
if err != nil {
return err
}
authGenState . Accounts = accounts
appGenState [ authtypes . ModuleName ] = clientCtx . Codec . MustMarshalJSON ( & authGenState )
// set the balances in the genesis state
var bankGenState banktypes . GenesisState
clientCtx . Codec . MustUnmarshalJSON ( appGenState [ banktypes . ModuleName ] , & bankGenState )
bankGenState . Balances = banktypes . SanitizeGenesisBalances ( genBalances )
for _ , bal := range bankGenState . Balances {
bankGenState . Supply = bankGenState . Supply . Add ( bal . Coins ... )
}
appGenState [ banktypes . ModuleName ] = clientCtx . Codec . MustMarshalJSON ( & bankGenState )
appGenStateJSON , err := json . MarshalIndent ( appGenState , "" , " " )
if err != nil {
return err
}
appGenesis := genutiltypes . NewAppGenesisWithVersion ( chainID , appGenStateJSON )
// generate empty genesis files for each validator and save
for i := 0 ; i < numValidators ; i ++ {
if err := appGenesis . SaveAs ( genFiles [ i ] ) ; err != nil {
return err
}
}
return nil
}
func collectGenFiles (
clientCtx client . Context , nodeConfig * cmtconfig . Config , chainID string ,
nodeIDs [ ] string , valPubKeys [ ] cryptotypes . PubKey , numValidators int ,
outputDir , nodeDirPrefix , nodeDaemonHome string , genBalIterator banktypes . GenesisBalancesIterator , valAddrCodec runtime . ValidatorAddressCodec ,
rpcPortStart , p2pPortStart int ,
singleMachine bool ,
) error {
var appState json . RawMessage
genTime := cmttime . Now ( )
for i := 0 ; i < numValidators ; i ++ {
var portOffset int
if singleMachine {
portOffset = i
}
nodeDirName := fmt . Sprintf ( "%s%d" , nodeDirPrefix , i )
nodeDir := filepath . Join ( outputDir , nodeDirName , nodeDaemonHome )
gentxsDir := filepath . Join ( outputDir , "gentxs" )
nodeConfig . Moniker = nodeDirName
nodeConfig . RPC . ListenAddress = fmt . Sprintf ( "tcp://0.0.0.0:%d" , rpcPortStart + portOffset )
nodeConfig . P2P . ListenAddress = fmt . Sprintf ( "tcp://0.0.0.0:%d" , p2pPortStart + portOffset )
nodeConfig . SetRoot ( nodeDir )
nodeID , valPubKey := nodeIDs [ i ] , valPubKeys [ i ]
initCfg := genutiltypes . NewInitConfig ( chainID , gentxsDir , nodeID , valPubKey )
appGenesis , err := genutiltypes . AppGenesisFromFile ( nodeConfig . GenesisFile ( ) )
if err != nil {
return err
}
nodeAppState , err := genutil . GenAppStateFromConfig ( clientCtx . Codec , clientCtx . TxConfig , nodeConfig , initCfg , appGenesis , genBalIterator , genutiltypes . DefaultMessageValidator ,
valAddrCodec )
if err != nil {
return err
}
if appState == nil {
// set the canonical application state (they should not differ)
appState = nodeAppState
}
genFile := nodeConfig . GenesisFile ( )
// overwrite each validator's genesis file to have a canonical genesis time
if err := genutil . ExportGenesisFileWithTime ( genFile , chainID , nil , appState , genTime ) ; err != nil {
return err
}
}
return nil
}
func getIP ( i int , startingIPAddr string ) ( ip string , err error ) {
if len ( startingIPAddr ) == 0 {
ip , err = server . ExternalIP ( )
if err != nil {
return "" , err
}
return ip , nil
}
return calculateIP ( startingIPAddr , i )
}
func calculateIP ( ip string , i int ) ( string , error ) {
ipv4 := net . ParseIP ( ip ) . To4 ( )
if ipv4 == nil {
return "" , fmt . Errorf ( "%v: non ipv4 address" , ip )
}
for j := 0 ; j < i ; j ++ {
ipv4 [ 3 ] ++
}
return ipv4 . String ( ) , nil
}
func writeFile ( name , dir string , contents [ ] byte ) error {
file := filepath . Join ( dir , name )
if err := os . MkdirAll ( dir , 0 o755 ) ; err != nil {
return fmt . Errorf ( "could not create directory %q: %w" , dir , err )
}
if err := os . WriteFile ( file , contents , 0 o600 ) ; err != nil {
return err
}
return nil
}
// startTestnet starts an in-process testnet
func startTestnet ( cmd * cobra . Command , args startArgs ) error {
networkConfig := network . DefaultConfig ( app . NewTestNetworkFixture )
// Default networkConfig.ChainID is random, and we should only override it if chainID provided
// is non-empty
if args . chainID != "" {
networkConfig . ChainID = args . chainID
}
networkConfig . SigningAlgo = args . algo
networkConfig . MinGasPrices = args . minGasPrices
networkConfig . NumValidators = args . numValidators
networkConfig . EnableLogging = args . enableLogging
networkConfig . RPCAddress = args . rpcAddress
networkConfig . APIAddress = args . apiAddress
networkConfig . GRPCAddress = args . grpcAddress
networkConfig . PrintMnemonic = args . printMnemonic
networkConfig . TimeoutCommit = args . timeoutCommit
networkLogger := network . NewCLILogger ( cmd )
baseDir := fmt . Sprintf ( "%s/%s" , args . outputDir , networkConfig . ChainID )
if _ , err := os . Stat ( baseDir ) ; ! os . IsNotExist ( err ) {
return fmt . Errorf (
"testnests directory already exists for chain-id '%s': %s, please remove or select a new --chain-id" ,
networkConfig . ChainID , baseDir )
}
testnet , err := network . New ( networkLogger , baseDir , networkConfig )
if err != nil {
return err
}
if _ , err := testnet . WaitForHeight ( 1 ) ; err != nil {
return err
}
cmd . Println ( "press the Enter Key to terminate" )
if _ , err := fmt . Scanln ( ) ; err != nil { // wait for Enter Key
return err
}
testnet . Cleanup ( )
return nil
}