From 4df9699821e7ed02152b2a6a66a628521a99d135 Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Mon, 28 Jul 2025 18:36:41 +0700 Subject: [PATCH 1/6] genesis wizard accept file input --- cicd/Dockerfile | 8 +- cicd/puppeth.sh | 2 + cmd/puppeth/puppeth.go | 12 +- cmd/puppeth/wizard.go | 4 +- cmd/puppeth/wizard_genesis.go | 289 ++++++++++++++++++++++++++-------- cmd/puppeth/wizard_intro.go | 56 +++---- common/types.go | 1 + 7 files changed, 266 insertions(+), 106 deletions(-) create mode 100755 cicd/puppeth.sh diff --git a/cicd/Dockerfile b/cicd/Dockerfile index 43dc061a3e..9baa552747 100644 --- a/cicd/Dockerfile +++ b/cicd/Dockerfile @@ -5,6 +5,9 @@ ENV GODEBUG=randseednop=0 RUN apk add make build-base linux-headers COPY . /builder + +RUN cd /builder && make puppeth + RUN cd /builder && make && mv /builder/build/bin/XDC /builder/build/bin/XDC-mainnet RUN mv /builder/common/constants/constants.go.testnet /builder/common/constants.go @@ -23,6 +26,8 @@ WORKDIR /work RUN apk add --no-cache bash curl + +COPY --from=builder /builder/build/bin/puppeth /usr/bin COPY --from=builder /builder/build/bin/XDC-local /usr/bin COPY --from=builder /builder/build/bin/XDC-devnet /usr/bin COPY --from=builder /builder/build/bin/XDC-testnet /usr/bin @@ -33,7 +38,8 @@ ADD cicd/local /work/local ADD cicd/devnet /work/devnet ADD cicd/testnet /work/testnet ADD cicd/mainnet /work/mainnet -ADD cicd/entry.sh /work/ +ADD cicd/entry.sh /work/entry.sh +ADD cicd/puppeth.sh /work/puppeth.sh # Create an empty pwd file RUN touch /work/.pwd diff --git a/cicd/puppeth.sh b/cicd/puppeth.sh new file mode 100755 index 0000000000..1c707cadfe --- /dev/null +++ b/cicd/puppeth.sh @@ -0,0 +1,2 @@ +#!/bin/bash +puppeth --inpath /app/generated/genesis_input.yml --outpath /app/generated/genesis.json \ No newline at end of file diff --git a/cmd/puppeth/puppeth.go b/cmd/puppeth/puppeth.go index 6989f95f62..9f77bda7e0 100644 --- a/cmd/puppeth/puppeth.go +++ b/cmd/puppeth/puppeth.go @@ -42,6 +42,16 @@ func main() { Value: 3, Usage: "log level to emit to the screen", }, + &cli.StringFlag{ + Name: "outpath", + Value: "", + Usage: "output genesis file path", + }, + &cli.StringFlag{ + Name: "inpath", + Value: "", + Usage: "input file to generate genesis file (optional)", + }, } app.Action = func(c *cli.Context) error { // Set up the logger to print everything and the random generator @@ -53,7 +63,7 @@ func main() { log.Crit("No spaces or hyphens allowed in network name") } // Start the wizard and relinquish control - makeWizard(c.String("network")).run() + makeWizard(c.String("network"), c.String("inpath"), c.String("outpath")).run() return nil } app.Run(os.Args) diff --git a/cmd/puppeth/wizard.go b/cmd/puppeth/wizard.go index da0c000c7e..efde23db86 100644 --- a/cmd/puppeth/wizard.go +++ b/cmd/puppeth/wizard.go @@ -38,7 +38,8 @@ import ( // config contains all the configurations needed by puppeth that should be saved // between sessions. type config struct { - path string // File containing the configuration values + path string // Output file containing the configuration values + inpath string // Input file to read genesis generation parameters (optional) bootnodes []string // Bootnodes to always connect to by all nodes ethstats string // Ethstats settings to cache for node deploys @@ -62,6 +63,7 @@ func (c config) flush() { os.MkdirAll(filepath.Dir(c.path), 0755) out, _ := json.MarshalIndent(c.Genesis, "", " ") + log.Warn("writing to file", "filename", c.path) if err := os.WriteFile(c.path, out, 0644); err != nil { log.Warn("Failed to save puppeth configs", "file", c.path, "err", err) } diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index 1fa7c2fafe..192ae03478 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -29,6 +29,7 @@ import ( "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/params" + "gopkg.in/yaml.v3" "context" "math/big" @@ -43,6 +44,66 @@ import ( "github.com/XinFinOrg/XDPoSChain/rlp" ) +type GenesisInput struct { + Name string + ChainId uint64 + Denom string + Period uint64 + Epoch uint64 + Gap uint64 + TimeoutPeriod int + TimeoutSyncThreshold int + V2SwitchBlock uint64 + CertThreshold float64 + MasternodesOwner common.Address + Masternodes []common.Address + StakingThreshold uint64 + RewardYield uint64 + FoundationWalletAddress common.Address +} + +func NewGenesisInput() *GenesisInput { + return &GenesisInput{ + Name: "xdc-custom-network", + ChainId: 5551, + Denom: "xdc", + Period: 2, + Epoch: 900, + Gap: 450, + TimeoutPeriod: 10, + TimeoutSyncThreshold: 3, + V2SwitchBlock: 0, + CertThreshold: 0.667, + StakingThreshold: 10_000_000, // 10M + RewardYield: 10, + FoundationWalletAddress: common.FoudationAddrBinary, + } +} + +func (w *wizard) loadGenesisInput() *GenesisInput { + input := NewGenesisInput() + file, err := os.Open(w.conf.inpath) + if err != nil { + log.Warn("Failed to open genesis input file", "err", err) + os.Exit(1) + return nil + } + defer file.Close() + + log.Warn("Decoding genesis input file", "path", w.conf.inpath) + log.Warn("File content", "file", file) + decoder := yaml.NewDecoder(file) + if err := decoder.Decode(&input); err != nil { + log.Warn("Failed to decode genesis input file (expect yaml format)", "err", err) + os.Exit(1) + return nil + } + fmt.Println("Generating genesis file with the below input") + fmt.Printf("%+v\n", input) + + return input +} + // makeGenesis creates a new genesis struct based on some user input. func (w *wizard) makeGenesis() { // Construct a default genesis block @@ -66,7 +127,13 @@ func (w *wizard) makeGenesis() { fmt.Println(" 2. Clique - proof-of-authority") fmt.Println(" 3. XDPoS - delegated-proof-of-stake") - choice := w.read() + input := w.loadGenesisInput() + var choice string + if input != nil { + choice = "3" + } else { + choice = w.read() + } switch { case choice == "1": // In case of ethash, we're pretty much done @@ -125,48 +192,75 @@ func (w *wizard) makeGenesis() { } fmt.Println() fmt.Println("How many seconds should blocks take? (default = 2)") - genesis.Config.XDPoS.Period = uint64(w.readDefaultInt(2)) + if input != nil { + genesis.Config.XDPoS.Period = input.Period + } else { + genesis.Config.XDPoS.Period = uint64(w.readDefaultInt(2)) + } genesis.Config.XDPoS.V2.CurrentConfig.MinePeriod = int(genesis.Config.XDPoS.Period) - fmt.Println() - fmt.Println("How many Ethers should be rewarded to masternode? (default = 10)") - genesis.Config.XDPoS.Reward = uint64(w.readDefaultInt(10)) - fmt.Println() fmt.Println("Which block number start v2 consesus? (default = 0)") - genesis.Config.XDPoS.V2.SwitchBlock = w.readDefaultBigInt(genesis.Config.XDPoS.V2.SwitchBlock) + if input != nil { + genesis.Config.XDPoS.V2.SwitchBlock = big.NewInt(int64(input.V2SwitchBlock)) + } else { + genesis.Config.XDPoS.V2.SwitchBlock = w.readDefaultBigInt(genesis.Config.XDPoS.V2.SwitchBlock) + } genesis.Config.XDPoS.V2.CurrentConfig.SwitchRound = 0 fmt.Println() fmt.Println("How long is the v2 timeout period? (default = 10)") - genesis.Config.XDPoS.V2.CurrentConfig.TimeoutPeriod = w.readDefaultInt(10) + if input != nil { + genesis.Config.XDPoS.V2.CurrentConfig.TimeoutPeriod = input.TimeoutPeriod + } else { + genesis.Config.XDPoS.V2.CurrentConfig.TimeoutPeriod = w.readDefaultInt(10) + } fmt.Println() fmt.Println("How many v2 timeout reach to send Synchronize message? (default = 3)") - genesis.Config.XDPoS.V2.CurrentConfig.TimeoutSyncThreshold = w.readDefaultInt(3) + if input != nil { + genesis.Config.XDPoS.V2.CurrentConfig.TimeoutSyncThreshold = input.TimeoutSyncThreshold + } else { + genesis.Config.XDPoS.V2.CurrentConfig.TimeoutSyncThreshold = w.readDefaultInt(3) + } fmt.Println() fmt.Printf("Proportion of total masternodes v2 vote collection to generate a QC (float value), should be two thirds of masternodes? (default = %f)\n", 0.667) - genesis.Config.XDPoS.V2.CurrentConfig.CertThreshold = w.readDefaultFloat(0.667) + if input != nil { + genesis.Config.XDPoS.V2.CurrentConfig.CertThreshold = input.CertThreshold + } else { + genesis.Config.XDPoS.V2.CurrentConfig.CertThreshold = w.readDefaultFloat(0.667) + } genesis.Config.XDPoS.V2.CurrentConfig.MaxMasternodes = 108 genesis.Config.XDPoS.V2.AllConfigs[0] = genesis.Config.XDPoS.V2.CurrentConfig fmt.Println() fmt.Println("Who own the first masternodes? (mandatory)") - owner := *w.readAddress() + var owner common.Address + if input != nil { + owner = input.MasternodesOwner + } else { + owner = *w.readAddress() + } // We also need the initial list of signers fmt.Println() - fmt.Println("Which accounts are allowed to seal (signers)? (mandatory at least one)") + fmt.Println("Which accounts are Masternodes? (mandatory at least one)") var signers []common.Address - for { - if address := w.readAddress(); address != nil { - signers = append(signers, *address) - continue + if input != nil { + for _, addr := range input.Masternodes { + signers = append(signers, addr) } - if len(signers) > 0 { - break + } else { + for { + if address := w.readAddress(); address != nil { + signers = append(signers, *address) + continue + } + if len(signers) > 0 { + break + } } } // Sort the signers and embed into the extra-data section @@ -177,6 +271,33 @@ func (w *wizard) makeGenesis() { } } } + + fmt.Println() + fmt.Println("How many blocks per epoch? (default = 900)") + if input != nil { + genesis.Config.XDPoS.Epoch = input.Epoch + } else { + genesis.Config.XDPoS.Epoch = uint64(w.readDefaultInt(900)) + } + genesis.Config.XDPoS.RewardCheckpoint = genesis.Config.XDPoS.Epoch + + fmt.Println() + fmt.Println("How many blocks before checkpoint need to prepare new set of masternodes? (default = 450)") + if input != nil { + genesis.Config.XDPoS.Gap = uint64(input.Gap) + } else { + genesis.Config.XDPoS.Gap = uint64(w.readDefaultInt(450)) + } + + fmt.Println() + fmt.Println("What is minimum staking threshold to become a Validator? (default = 10M)") + threshold := new(big.Int) + if input != nil { + threshold.SetString("10000000000000000000", 10) // 10M + } else { + threshold.SetString("10000000000000000000", 10) // 10M + } + validatorCap := new(big.Int) validatorCap.SetString("50000000000000000000000", 10) var validatorCaps []*big.Int @@ -187,18 +308,29 @@ func (w *wizard) makeGenesis() { } fmt.Println() - fmt.Println("How many blocks per epoch? (default = 900)") - epochNumber := uint64(w.readDefaultInt(900)) - genesis.Config.XDPoS.Epoch = epochNumber - genesis.Config.XDPoS.RewardCheckpoint = epochNumber + // fmt.Println("How many Ethers should be rewarded to masternode each Epoch? (default = 10)") + fmt.Println("What should be the reward yield of Masternodes in APY% (default = 10)") + yield := uint64(0) + if input != nil { + yield = input.RewardYield + } else { + yield = uint64(w.readDefaultInt(10)) + } + blocksPerYear := uint64(31536000 / genesis.Config.XDPoS.Period) + epochsPerYear := blocksPerYear / genesis.Config.XDPoS.Epoch + rewardsPerYear := float64(threshold.Uint64()) * (float64(yield) / float64(100)) + rewardPerEpoch := uint64(rewardsPerYear / float64(epochsPerYear)) + fmt.Println() + fmt.Println("Calculated Masternode reward per epoch based on yield: ", rewardPerEpoch) + genesis.Config.XDPoS.Reward = rewardPerEpoch fmt.Println() - fmt.Println("How many blocks before checkpoint need to prepare new set of masternodes? (default = 450)") - genesis.Config.XDPoS.Gap = uint64(w.readDefaultInt(450)) - - fmt.Println() - fmt.Println("What is foundation wallet address? (default = xdc0000000000000000000000000000000000000068)") - genesis.Config.XDPoS.FoudationWalletAddr = w.readDefaultAddress(common.FoudationAddrBinary) + fmt.Println("What is foundation wallet address (collect 10% of all rewards)? (default = xdc0000000000000000000000000000000000000068)") + if input != nil { + genesis.Config.XDPoS.FoudationWalletAddr = input.FoundationWalletAddress + } else { + genesis.Config.XDPoS.FoudationWalletAddr = w.readDefaultAddress(common.FoudationAddrBinary) + } // Validator Smart Contract Code pKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") @@ -235,21 +367,31 @@ func (w *wizard) makeGenesis() { fmt.Println() fmt.Println("Which accounts are allowed to confirm in Foudation MultiSignWallet?") var owners []common.Address - for { - if address := w.readAddress(); address != nil { - owners = append(owners, *address) - continue - } - if len(owners) > 0 { - break + if input != nil { + owners = append(owners, input.MasternodesOwner) + } else { + for { + if address := w.readAddress(); address != nil { + owners = append(owners, *address) + continue + } + if len(owners) > 0 { + break + } } } + fmt.Println() - fmt.Println("How many require for confirm tx in Foudation MultiSignWallet? (default = 2)") - required := int64(w.readDefaultInt(2)) + fmt.Println("How many require for confirm tx in Foudation MultiSignWallet? (default = 1)") + var required uint64 + if input != nil { + required = 1 + } else { + required = uint64(w.readDefaultInt(1)) + } // MultiSigWallet. - multiSignWalletAddr, _, err := multiSignWalletContract.DeployMultiSigWallet(transactOpts, contractBackend, owners, big.NewInt(required)) + multiSignWalletAddr, _, err := multiSignWalletContract.DeployMultiSigWallet(transactOpts, contractBackend, owners, big.NewInt(int64(required))) if err != nil { fmt.Println("Can't deploy MultiSignWallet SMC") } @@ -267,7 +409,7 @@ func (w *wizard) makeGenesis() { } // Block Signers Smart Contract - blockSignerAddress, _, err := blockSignerContract.DeployBlockSigner(transactOpts, contractBackend, big.NewInt(int64(epochNumber))) + blockSignerAddress, _, err := blockSignerContract.DeployBlockSigner(transactOpts, contractBackend, big.NewInt(int64(genesis.Config.XDPoS.Epoch))) if err != nil { fmt.Println("Can't deploy root registry") } @@ -301,21 +443,31 @@ func (w *wizard) makeGenesis() { fmt.Println() fmt.Println("Which accounts are allowed to confirm in Team MultiSignWallet?") var teams []common.Address - for { - if address := w.readAddress(); address != nil { - teams = append(teams, *address) - continue - } - if len(teams) > 0 { - break + if input != nil { + owners = append(owners, input.MasternodesOwner) + } else { + for { + if address := w.readAddress(); address != nil { + teams = append(teams, *address) + continue + } + if len(teams) > 0 { + break + } } } + fmt.Println() fmt.Println("How many require for confirm tx in Team MultiSignWallet? (default = 2)") - required = int64(w.readDefaultInt(2)) + var requiredTeam int64 + if input != nil { + requiredTeam = 1 + } else { + requiredTeam = int64(w.readDefaultInt(1)) + } // MultiSigWallet. - multiSignWalletTeamAddr, _, err := multiSignWalletContract.DeployMultiSigWallet(transactOpts, contractBackend, teams, big.NewInt(required)) + multiSignWalletTeamAddr, _, err := multiSignWalletContract.DeployMultiSigWallet(transactOpts, contractBackend, teams, big.NewInt(requiredTeam)) if err != nil { fmt.Println("Can't deploy MultiSignWallet SMC") } @@ -337,32 +489,33 @@ func (w *wizard) makeGenesis() { Storage: storage, } - fmt.Println() - fmt.Println("What is swap wallet address for fund 55m XDC?") - swapAddr := *w.readAddress() - baseBalance := big.NewInt(0) // 55m - baseBalance.Add(baseBalance, big.NewInt(55*1000*1000)) - baseBalance.Mul(baseBalance, big.NewInt(1000000000000000000)) - genesis.Alloc[swapAddr] = types.Account{ - Balance: baseBalance, - } - default: log.Crit("Invalid consensus engine choice", "choice", choice) } // Consensus all set, just ask for initial funds and go fmt.Println() fmt.Println("Which accounts should be pre-funded? (advisable at least one)") - for { - // Read the address of the account to fund - if address := w.readAddress(); address != nil { - genesis.Alloc[*address] = types.Account{ - Balance: new(big.Int).Lsh(big.NewInt(1), 256-7), // 2^256 / 128 (allow many pre-funds without balance overflows) + var addresses []common.Address + if input != nil { + addresses = append(addresses, input.MasternodesOwner) + } else { + for { + if address := w.readAddress(); address != nil { + addresses = append(addresses, *address) + continue } - continue + break } - break } + for _, address := range addresses { + baseBalance := big.NewInt(0) // 21m + baseBalance.Add(baseBalance, big.NewInt(21*1000*1000)) + baseBalance.Mul(baseBalance, big.NewInt(1000000000000000000)) + genesis.Alloc[address] = types.Account{ + Balance: baseBalance, + } + } + // Add a batch of precompile balances to avoid them getting deleted for i := int64(0); i < 2; i++ { genesis.Alloc[common.BigToAddress(big.NewInt(i))] = types.Account{Balance: big.NewInt(0)} @@ -370,7 +523,11 @@ func (w *wizard) makeGenesis() { // Query the user for some custom extras fmt.Println() fmt.Println("Specify your chain/network ID if you want an explicit one (default = random)") - genesis.Config.ChainID = new(big.Int).SetUint64(uint64(w.readDefaultInt(rand.Intn(65536)))) + if input != nil { + genesis.Config.ChainID = new(big.Int).SetUint64(input.ChainId) + } else { + genesis.Config.ChainID = new(big.Int).SetUint64(uint64(w.readDefaultInt(rand.Intn(65536)))) + } // All done, store the genesis and flush to disk log.Info("Configured new genesis block") diff --git a/cmd/puppeth/wizard_intro.go b/cmd/puppeth/wizard_intro.go index 39810b9a58..2ce267ad90 100644 --- a/cmd/puppeth/wizard_intro.go +++ b/cmd/puppeth/wizard_intro.go @@ -18,23 +18,31 @@ package main import ( "bufio" - "encoding/json" "fmt" "os" "path/filepath" "strings" - "sync" "github.com/XinFinOrg/XDPoSChain/log" ) // makeWizard creates and returns a new puppeth wizard. -func makeWizard(network string) *wizard { +func makeWizard(network string, inputPath string, outputPath string) *wizard { + conf := config{ + Servers: make(map[string][]byte), + } + if inputPath != "" { + conf.inpath = inputPath + } + if outputPath != "" { + conf.path = outputPath + } else { + conf.path = filepath.Join(os.Getenv("HOME"), ".puppeth", network) + } + return &wizard{ - network: network, - conf: config{ - Servers: make(map[string][]byte), - }, + network: network, + conf: conf, servers: make(map[string]*sshClient), services: make(map[string][]string), in: bufio.NewReader(os.Stdin), @@ -44,6 +52,10 @@ func makeWizard(network string) *wizard { // run displays some useful infos to the user, starting on the journey of // setting up a new or managing an existing Ethereum private network. func (w *wizard) run() { + if w.conf.inpath != "" { //don't use interactive mode if run with input option + w.makeGenesis() + return + } fmt.Println("+-----------------------------------------------------------+") fmt.Println("| Welcome to puppeth, your Ethereum private network manager |") fmt.Println("| |") @@ -72,36 +84,6 @@ func (w *wizard) run() { } log.Info("Administering Ethereum network", "name", w.network) - // Load initial configurations and connect to all live servers - w.conf.path = filepath.Join(os.Getenv("HOME"), ".puppeth", w.network) - - blob, err := os.ReadFile(w.conf.path) - if err != nil { - log.Warn("No previous configurations found", "path", w.conf.path) - } else if err := json.Unmarshal(blob, &w.conf); err != nil { - log.Crit("Previous configuration corrupted", "path", w.conf.path, "err", err) - } else { - // Dial all previously known servers concurrently - var pend sync.WaitGroup - for server, pubkey := range w.conf.Servers { - pend.Add(1) - - go func(server string, pubkey []byte) { - defer pend.Done() - - log.Info("Dialing previously configured server", "server", server) - client, err := dial(server, pubkey) - if err != nil { - log.Error("Previous server unreachable", "server", server, "err", err) - } - w.lock.Lock() - w.servers[server] = client - w.lock.Unlock() - }(server, pubkey) - } - pend.Wait() - w.networkStats() - } // Basics done, loop ad infinitum about what to do for { fmt.Println() diff --git a/common/types.go b/common/types.go index d6a68c8ba9..74990ce823 100644 --- a/common/types.go +++ b/common/types.go @@ -72,6 +72,7 @@ var ( XDCNativeAddressBinary = HexToAddress("0x0000000000000000000000000000000000000001") LendingLockAddressBinary = HexToAddress("0x0000000000000000000000000000000000000011") MintedRecordAddressBinary = HexToAddress("0x000000000000000000000000000000000000009a") + SwapAddressBinary = HexToAddress("0x000000000000000000000000000000000000008e") //confirm Address ) // Hash represents the 32 byte Keccak256 hash of arbitrary data. From 8e07f0678f3024cbcd25ac17831f8d7f12fe0c61 Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Thu, 3 Jul 2025 04:16:37 +0700 Subject: [PATCH 2/6] fix local start script --- cicd/local/start.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cicd/local/start.sh b/cicd/local/start.sh index 30a4ed4464..1302b30ce7 100755 --- a/cicd/local/start.sh +++ b/cicd/local/start.sh @@ -49,8 +49,7 @@ XDC --ethstats ${netstats} \ --bootnodes ${bootnodes} \ --syncmode full \ --datadir /work/xdcchain \ ---networkid 551 \ --port $port \ +--port $port \ --rpc --rpccorsdomain "*" \ --rpcaddr 0.0.0.0 \ --rpcport $rpc_port \ From 069cd8ebce87c0a961a49ce1edcee4848e8d08e7 Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Thu, 10 Jul 2025 10:56:53 +0700 Subject: [PATCH 3/6] fix wrong storage in genesis due to rlp changed behavior (EIP-2718) --- cmd/puppeth/wizard_genesis.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index 192ae03478..a2197bfffd 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -41,7 +41,6 @@ import ( randomizeContract "github.com/XinFinOrg/XDPoSChain/contracts/randomize" validatorContract "github.com/XinFinOrg/XDPoSChain/contracts/validator" "github.com/XinFinOrg/XDPoSChain/crypto" - "github.com/XinFinOrg/XDPoSChain/rlp" ) type GenesisInput struct { @@ -350,10 +349,7 @@ func (w *wizard) makeGenesis() { code, _ := contractBackend.CodeAt(ctx, validatorAddress, nil) storage := make(map[common.Hash]common.Hash) f := func(key, val common.Hash) bool { - decode := []byte{} - trim := bytes.TrimLeft(val.Bytes(), "\x00") - rlp.DecodeBytes(trim, &decode) - storage[key] = common.BytesToHash(decode) + storage[key] = common.BytesToHash(val.Bytes()) log.Info("DecodeBytes", "value", val.String(), "decode", storage[key].String()) return true } From a1e5a9837758c015987c26499e1199fbfb48712c Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Mon, 25 Aug 2025 16:06:07 +0400 Subject: [PATCH 4/6] update validator initial configs --- cicd/local/start.sh | 102 +++++++++++++++++++------- cmd/puppeth/wizard_genesis.go | 39 +++++----- common/types.go | 1 - contracts/validator/validator.go | 24 +++--- contracts/validator/validator_test.go | 4 +- 5 files changed, 114 insertions(+), 56 deletions(-) diff --git a/cicd/local/start.sh b/cicd/local/start.sh index 1302b30ce7..886f913026 100755 --- a/cicd/local/start.sh +++ b/cicd/local/start.sh @@ -1,6 +1,4 @@ #!/bin/bash -set -eo pipefail - if [ ! -d /work/xdcchain/XDC/chaindata ] then if test -z "$PRIVATE_KEY" @@ -26,41 +24,95 @@ do bootnodes="${bootnodes},$line" fi done < "$input" +#check last line since it's not included in "read" command https://stackoverflow.com/questions/12916352/shell-script-read-missing-last-line +if [ -z "${bootnodes}" ] +then + bootnodes=$line +else + bootnodes="${bootnodes},$line" +fi -log_level="${LOG_LEVEL:-3}" +log_level=3 +if test -z "$LOG_LEVEL" +then + echo "Log level not set, default to verbosity of $log_level" +else + echo "Log level found, set to $LOG_LEVEL" + log_level=$LOG_LEVEL +fi -port="${PORT:-30303}" +port=30303 +if test -z "$PORT" +then + echo "PORT not set, default to $port" +else + echo "PORT found, set to $PORT" + port=$PORT +fi -rpc_port="${RPC_PORT:-8545}" +rpc_port=8545 +if test -z "$RPC_PORT" +then + echo "RPC_PORT not set, default to $rpc_port" +else + echo "RPC_PORT found, set to $RPC_PORT" + rpc_port=$RPC_PORT +fi -ws_port="${WS_PORT:-8555}" +ws_port=8555 +if test -z "$WS_PORT" +then + echo "WS_PORT not set, default to $ws_port" +else + echo "WS_PORT found, set to $WS_PORT" + ws_port=$WS_PORT +fi -netstats="${NODE_NAME}-${wallet}:xinfin_xdpos_hybrid_network_stats@devnetstats.apothem.network:2000" +instance_ip=$(ifconfig eth0 | awk '/inet addr:/ {print $2}' | cut -d: -f2) +if test -z "$INSTANCE_IP" +then + echo "INSTANCE_IP not set, default to $instance_ip" +else + echo "INSTANCE_IP found, set to $INSTANCE_IP" + instance_ip=$INSTANCE_IP +fi + +sync_mode=full +if test -z "$SYNC_MODE" +then + echo "SYNC_MODE not set, default to full" #full or fast +else + echo "SYNC_MODE found, set to $SYNC_MODE" + sync_mode=$SYNC_MODE +fi + +gc_mode=archive +if test -z "$GC_MODE" +then + echo "GC_MODE not set, default to archive" #full or archive +else + echo "GC_MODE found, set to $GC_MODE" + gc_mode=$GC_MODE +fi -echo "Running a node with wallet: ${wallet}" +echo "Running a node with wallet: ${wallet} at IP: ${instance_ip}" echo "Starting nodes with $bootnodes ..." # Note: --gcmode=archive means node will store all historical data. This will lead to high memory usage. But sync mode require archive to sync # https://github.com/XinFinOrg/XDPoSChain/issues/268 -XDC --ethstats ${netstats} \ ---gcmode archive \ +XDC \ +--gcmode ${gc_mode} --syncmode ${sync_mode} \ +--nat extip:${instance_ip} \ --bootnodes ${bootnodes} \ ---syncmode full \ --datadir /work/xdcchain \ ---port $port \ ---rpc --rpccorsdomain "*" \ ---rpcaddr 0.0.0.0 \ ---rpcport $rpc_port \ ---rpcapi db,eth,debug,net,shh,txpool,personal,web3,XDPoS \ ---rpcvhosts "*" \ ---unlock "${wallet}" \ ---password /work/.pwd --mine \ ---gasprice "1" --targetgaslimit "420000000" \ ---verbosity ${log_level} \ +--port $port --http --http-corsdomain "*" --http-addr 0.0.0.0 \ +--http-port $rpc_port \ +--http-api db,eth,net,txpool,web3,XDPoS \ +--http-vhosts "*" --unlock "${wallet}" --password /work/.pwd --mine \ +--miner-gasprice "1" --miner-gaslimit "50000000" --verbosity ${log_level} \ --debugdatadir /work/xdcchain \ ---ws \ ---wsaddr=0.0.0.0 \ ---wsport $ws_port \ ---wsorigins "*" 2>&1 >>/work/xdcchain/xdc.log | tee -a /work/xdcchain/xdc.log +--store-reward \ +--ws --ws-addr=0.0.0.0 --ws-port $ws_port \ +--ws-origins "*" 2>&1 >>/work/xdcchain/xdc.log | tee -a /work/xdcchain/xdc.log diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index a2197bfffd..8f84ec911f 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -290,20 +290,11 @@ func (w *wizard) makeGenesis() { fmt.Println() fmt.Println("What is minimum staking threshold to become a Validator? (default = 10M)") - threshold := new(big.Int) + var threshold uint64 if input != nil { - threshold.SetString("10000000000000000000", 10) // 10M + threshold = input.StakingThreshold } else { - threshold.SetString("10000000000000000000", 10) // 10M - } - - validatorCap := new(big.Int) - validatorCap.SetString("50000000000000000000000", 10) - var validatorCaps []*big.Int - genesis.ExtraData = make([]byte, 32+len(signers)*common.AddressLength+crypto.SignatureLength) - for i, signer := range signers { - validatorCaps = append(validatorCaps, validatorCap) - copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:]) + threshold = uint64(w.readDefaultInt(10000000)) } fmt.Println() @@ -317,11 +308,12 @@ func (w *wizard) makeGenesis() { } blocksPerYear := uint64(31536000 / genesis.Config.XDPoS.Period) epochsPerYear := blocksPerYear / genesis.Config.XDPoS.Epoch - rewardsPerYear := float64(threshold.Uint64()) * (float64(yield) / float64(100)) - rewardPerEpoch := uint64(rewardsPerYear / float64(epochsPerYear)) + rewardsPerYear := float64(threshold) * (float64(yield) / float64(100)) + rewardPerEpochPerMN := uint64(rewardsPerYear / float64(epochsPerYear)) + totalRewardPerEpoch := rewardPerEpochPerMN * uint64(len(signers)) fmt.Println() - fmt.Println("Calculated Masternode reward per epoch based on yield: ", rewardPerEpoch) - genesis.Config.XDPoS.Reward = rewardPerEpoch + fmt.Println("Calculated Total Masternode rewards per epoch based on yield: ", totalRewardPerEpoch) + genesis.Config.XDPoS.Reward = totalRewardPerEpoch fmt.Println() fmt.Println("What is foundation wallet address (collect 10% of all rewards)? (default = xdc0000000000000000000000000000000000000068)") @@ -337,7 +329,16 @@ func (w *wizard) makeGenesis() { contractBackend := backends.NewXDCSimulatedBackend(types.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}, 10000000, params.TestXDPoSMockChainConfig) transactOpts := bind.NewKeyedTransactor(pKey) - validatorAddress, _, err := validatorContract.DeployValidator(transactOpts, contractBackend, signers, validatorCaps, owner) + minDeposit := new(big.Int).SetUint64(threshold) + minDeposit.Mul(minDeposit, big.NewInt(1e18)) //convert to wei + validatorCap := new(big.Int).Set(minDeposit) + var validatorCaps []*big.Int + genesis.ExtraData = make([]byte, 32+len(signers)*common.AddressLength+crypto.SignatureLength) + for i, signer := range signers { + validatorCaps = append(validatorCaps, validatorCap) + copy(genesis.ExtraData[32+i*common.AddressLength:], signer[:]) + } + validatorAddress, _, err := validatorContract.DeployValidator(transactOpts, contractBackend, signers, validatorCaps, owner, minDeposit, nil) if err != nil { fmt.Println("Can't deploy root registry") } @@ -505,8 +506,8 @@ func (w *wizard) makeGenesis() { } for _, address := range addresses { baseBalance := big.NewInt(0) // 21m - baseBalance.Add(baseBalance, big.NewInt(21*1000*1000)) - baseBalance.Mul(baseBalance, big.NewInt(1000000000000000000)) + baseBalance.Add(baseBalance, big.NewInt(21_000_000)) + baseBalance.Mul(baseBalance, big.NewInt(1e18)) genesis.Alloc[address] = types.Account{ Balance: baseBalance, } diff --git a/common/types.go b/common/types.go index 74990ce823..d6a68c8ba9 100644 --- a/common/types.go +++ b/common/types.go @@ -72,7 +72,6 @@ var ( XDCNativeAddressBinary = HexToAddress("0x0000000000000000000000000000000000000001") LendingLockAddressBinary = HexToAddress("0x0000000000000000000000000000000000000011") MintedRecordAddressBinary = HexToAddress("0x000000000000000000000000000000000000009a") - SwapAddressBinary = HexToAddress("0x000000000000000000000000000000000000008e") //confirm Address ) // Hash represents the 32 byte Keccak256 hash of arbitrary data. diff --git a/contracts/validator/validator.go b/contracts/validator/validator.go index 5aa54967a0..1c3c5969cd 100644 --- a/contracts/validator/validator.go +++ b/contracts/validator/validator.go @@ -43,17 +43,23 @@ func NewValidator(transactOpts *bind.TransactOpts, contractAddr common.Address, }, nil } -func DeployValidator(transactOpts *bind.TransactOpts, contractBackend bind.ContractBackend, validatorAddress []common.Address, caps []*big.Int, ownerAddress common.Address) (common.Address, *Validator, error) { - minDeposit := new(big.Int) - minDeposit.SetString("10000000000000000000000000", 10) - minVoterCap := new(big.Int) - minVoterCap.SetString("25000000000000000000000", 10) - // Deposit 50K XDC - // Min Voter Cap 10 XDC - // 150 masternodes +func DeployValidator(transactOpts *bind.TransactOpts, contractBackend bind.ContractBackend, validatorAddress []common.Address, caps []*big.Int, ownerAddress common.Address, minDeposit *big.Int, minVoterCap *big.Int) (common.Address, *Validator, error) { + if minDeposit == nil { + minDeposit = new(big.Int) + minDeposit.SetString("10000000", 10) // 10M + minDeposit.Mul(minDeposit, big.NewInt(1e18)) //convert to wei + } + if minVoterCap == nil { + minVoterCap = new(big.Int).Set(minDeposit) + minVoterCap.Div(minVoterCap, big.NewInt(400)) //set votercap to 0.25% of candidate deposit (25K XDC) + } + + // Deposit 10M XDC + // Min Voter Cap 25K XDC + // 108 masternodes // Candidate Delay Withdraw 30 days = 1296000 blocks // Voter Delay Withdraw 10 days = 432000 blocks - validatorAddr, _, _, err := contract.DeployXDCValidator(transactOpts, contractBackend, validatorAddress, caps, ownerAddress, minDeposit, minVoterCap, big.NewInt(18), big.NewInt(1296000), big.NewInt(432000)) + validatorAddr, _, _, err := contract.DeployXDCValidator(transactOpts, contractBackend, validatorAddress, caps, ownerAddress, minDeposit, minVoterCap, big.NewInt(108), big.NewInt(1296000), big.NewInt(432000)) if err != nil { return validatorAddr, nil, err } diff --git a/contracts/validator/validator_test.go b/contracts/validator/validator_test.go index 8543efd081..b794b5c337 100644 --- a/contracts/validator/validator_test.go +++ b/contracts/validator/validator_test.go @@ -56,7 +56,7 @@ func TestValidator(t *testing.T) { validatorCap := new(big.Int) validatorCap.SetString("50000000000000000000000", 10) - validatorAddress, validator, err := DeployValidator(transactOpts, contractBackend, []common.Address{addr}, []*big.Int{validatorCap}, addr) + validatorAddress, validator, err := DeployValidator(transactOpts, contractBackend, []common.Address{addr}, []*big.Int{validatorCap}, addr, nil, nil) if err != nil { t.Fatalf("can't deploy root registry: %v", err) } @@ -280,7 +280,7 @@ func TestStatedbUtils(t *testing.T) { contractBackend := backends.NewXDCSimulatedBackend(genesisAlloc, 10000000, params.TestXDPoSMockChainConfig) transactOpts := bind.NewKeyedTransactor(key) - validatorAddress, _, err := DeployValidator(transactOpts, contractBackend, []common.Address{addr, acc3Addr}, []*big.Int{validatorCap, validatorCap}, addr) + validatorAddress, _, err := DeployValidator(transactOpts, contractBackend, []common.Address{addr, acc3Addr}, []*big.Int{validatorCap, validatorCap}, addr, nil, nil) if err != nil { t.Fatalf("can't deploy root registry: %v", err) } From ae696dc547721dd0defb2fd4fe13d90d4ace12fe Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Sun, 14 Sep 2025 15:21:26 +0400 Subject: [PATCH 5/6] func CopyConstants choose local chain if unknown chainID --- cmd/puppeth/wizard_genesis.go | 8 ++++++++ common/constants.all.go | 8 ++++---- common/constants.local.go | 6 +++--- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index 8f84ec911f..e0e0460aa5 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -231,6 +231,14 @@ func (w *wizard) makeGenesis() { genesis.Config.XDPoS.V2.CurrentConfig.CertThreshold = w.readDefaultFloat(0.667) } genesis.Config.XDPoS.V2.CurrentConfig.MaxMasternodes = 108 + //TODO: config to add after rewards upgrade enabled + // genesis.Config.XDPoS.V2.CurrentConfig.MaxProtectornodes + // genesis.Config.XDPoS.V2.CurrentConfig.MaxObservernodes + // genesis.Config.XDPoS.V2.CurrentConfig.MinProtectornodes + // genesis.Config.XDPoS.V2.CurrentConfig.MasternodeReward + // genesis.Config.XDPoS.V2.CurrentConfig.ProtectornodeReward + // genesis.Config.XDPoS.V2.CurrentConfig.ObservernodeReward + genesis.Config.XDPoS.V2.AllConfigs[0] = genesis.Config.XDPoS.V2.CurrentConfig fmt.Println() diff --git a/common/constants.all.go b/common/constants.all.go index cbf664fd5d..9d3425d709 100644 --- a/common/constants.all.go +++ b/common/constants.all.go @@ -128,15 +128,15 @@ func IsInBlacklist(address *Address) bool { // It skips mainnet since the default value is from mainnet. func CopyConstants(chainID uint64) { var c *constant - if chainID == TestnetConstant.chainID { + if chainID == MaintnetConstant.chainID { + return + } else if chainID == TestnetConstant.chainID { c = &TestnetConstant IsTestnet = true } else if chainID == DevnetConstant.chainID { c = &DevnetConstant - } else if chainID == localConstant.chainID { + } else { // local custom chain, it can have any chainID c = &localConstant - } else { - return } MaxMasternodesV2 = c.maxMasternodesV2 diff --git a/common/constants.local.go b/common/constants.local.go index aeec55f669..291d2871de 100644 --- a/common/constants.local.go +++ b/common/constants.local.go @@ -28,9 +28,9 @@ var localConstant = constant{ tipXDCXReceiverDisable: big.NewInt(0), eip1559Block: big.NewInt(0), cancunBlock: big.NewInt(0), - tipUpgradeReward: big.NewInt(0), - tipUpgradePenalty: big.NewInt(0), - tipEpochHalving: big.NewInt(0), + tipUpgradeReward: big.NewInt(999999999), + tipUpgradePenalty: big.NewInt(999999999), + tipEpochHalving: big.NewInt(999999999), trc21IssuerSMC: HexToAddress("0x8c0faeb5C6bEd2129b8674F262Fd45c4e9468bee"), xdcxListingSMC: HexToAddress("0xDE34dD0f536170993E8CFF639DdFfCF1A85D3E53"), From 30e1a9a7fd5a9b8d3fc93a2d68602572ef35652f Mon Sep 17 00:00:00 2001 From: wanwiset25 Date: Tue, 16 Sep 2025 03:24:36 +0400 Subject: [PATCH 6/6] fix --- cicd/Dockerfile | 1 - cicd/local/start.sh | 7 ------- cmd/puppeth/wizard.go | 2 +- cmd/puppeth/wizard_genesis.go | 2 +- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/cicd/Dockerfile b/cicd/Dockerfile index 9baa552747..79af8bccf7 100644 --- a/cicd/Dockerfile +++ b/cicd/Dockerfile @@ -26,7 +26,6 @@ WORKDIR /work RUN apk add --no-cache bash curl - COPY --from=builder /builder/build/bin/puppeth /usr/bin COPY --from=builder /builder/build/bin/XDC-local /usr/bin COPY --from=builder /builder/build/bin/XDC-devnet /usr/bin diff --git a/cicd/local/start.sh b/cicd/local/start.sh index 886f913026..18fa4c6ebc 100755 --- a/cicd/local/start.sh +++ b/cicd/local/start.sh @@ -24,13 +24,6 @@ do bootnodes="${bootnodes},$line" fi done < "$input" -#check last line since it's not included in "read" command https://stackoverflow.com/questions/12916352/shell-script-read-missing-last-line -if [ -z "${bootnodes}" ] -then - bootnodes=$line -else - bootnodes="${bootnodes},$line" -fi log_level=3 if test -z "$LOG_LEVEL" diff --git a/cmd/puppeth/wizard.go b/cmd/puppeth/wizard.go index efde23db86..aa33da5df8 100644 --- a/cmd/puppeth/wizard.go +++ b/cmd/puppeth/wizard.go @@ -39,7 +39,7 @@ import ( // between sessions. type config struct { path string // Output file containing the configuration values - inpath string // Input file to read genesis generation parameters (optional) + inpath string // Input file to read genesis generation parameters (optional) bootnodes []string // Bootnodes to always connect to by all nodes ethstats string // Ethstats settings to cache for node deploys diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index e0e0460aa5..8abc778090 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -231,7 +231,7 @@ func (w *wizard) makeGenesis() { genesis.Config.XDPoS.V2.CurrentConfig.CertThreshold = w.readDefaultFloat(0.667) } genesis.Config.XDPoS.V2.CurrentConfig.MaxMasternodes = 108 - //TODO: config to add after rewards upgrade enabled + // TODO: config to add after rewards upgrade enabled // genesis.Config.XDPoS.V2.CurrentConfig.MaxProtectornodes // genesis.Config.XDPoS.V2.CurrentConfig.MaxObservernodes // genesis.Config.XDPoS.V2.CurrentConfig.MinProtectornodes