diff --git a/TESTING.md b/TESTING.md
new file mode 100644
index 0000000000..47d2d4d8a8
--- /dev/null
+++ b/TESTING.md
@@ -0,0 +1,263 @@
+# XDPoS Consensus Testing Guide
+
+This document describes how to test the XDPoS consensus implementation for syncing with XDC Mainnet and Apothem Testnet.
+
+## Prerequisites
+
+- Go 1.21 or higher
+- Git
+- At least 500GB disk space for full sync (mainnet)
+- Good network connection
+
+## Building
+
+```bash
+# Clone the repository
+git clone https://github.com/AnilChinchawale/go-ethereum.git
+cd go-ethereum
+git checkout feature/xdpos-consensus
+
+# Build the XDC binary
+make XDC
+
+# Or build all tools
+make all
+```
+
+## Network Configuration
+
+### XDC Mainnet
+- **Chain ID:** 50
+- **Network ID:** 50
+- **Block Time:** 2 seconds
+- **Epoch:** 900 blocks (~30 minutes)
+- **Consensus:** XDPoS (Delegated Proof of Stake)
+- **P2P Port:** 30304 (default for XDC)
+
+### XDC Apothem Testnet
+- **Chain ID:** 51
+- **Network ID:** 51
+- **Block Time:** 2 seconds
+- **Epoch:** 900 blocks (~30 minutes)
+
+## Running a Node
+
+### Full Sync (XDC Mainnet)
+
+```bash
+# Initialize with genesis (first time only)
+./build/bin/XDC init genesis/xdc_mainnet.json --datadir ~/.xdc
+
+# Start sync
+./build/bin/XDC \
+ --networkid 50 \
+ --datadir ~/.xdc \
+ --syncmode full \
+ --port 30304 \
+ --bootnodes "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@81.0.220.137:30304,enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@5.189.144.192:30304,enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@154.53.42.5:30304"
+```
+
+### Light Sync
+
+```bash
+./build/bin/XDC \
+ --networkid 50 \
+ --datadir ~/.xdc-light \
+ --syncmode light \
+ --port 30305 \
+ --bootnodes "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@81.0.220.137:30304"
+```
+
+### Apothem Testnet
+
+```bash
+# Initialize with genesis
+./build/bin/XDC init genesis/xdc_apothem.json --datadir ~/.xdc-testnet
+
+# Start sync
+./build/bin/XDC \
+ --networkid 51 \
+ --datadir ~/.xdc-testnet \
+ --syncmode full \
+ --port 30304
+```
+
+## Verifying Sync
+
+### Check Sync Status
+
+```bash
+# Attach to running node
+./build/bin/XDC attach ~/.xdc/XDC.ipc
+
+# In console
+> eth.syncing
+> eth.blockNumber
+> admin.peers
+```
+
+### Expected Output
+
+A syncing node should show:
+```javascript
+> eth.syncing
+{
+ currentBlock: 1234567,
+ highestBlock: 9876543,
+ knownStates: 0,
+ pulledStates: 0,
+ startingBlock: 0
+}
+
+> admin.peers.length
+5 // Should have several peers
+```
+
+### Check Consensus
+
+```javascript
+// Get current block
+> eth.getBlock("latest")
+
+// Verify XDPoS fields
+> eth.getBlock("latest").difficulty
+2 // Should be 1 or 2 (in-turn/out-of-turn)
+
+// Check block time
+> eth.getBlock("latest").timestamp - eth.getBlock(eth.blockNumber - 1).timestamp
+2 // Should be ~2 seconds
+```
+
+## RPC Endpoints
+
+Enable RPC for external access:
+
+```bash
+./build/bin/XDC \
+ --networkid 50 \
+ --datadir ~/.xdc \
+ --http \
+ --http.addr "0.0.0.0" \
+ --http.port 8545 \
+ --http.api "eth,net,web3,xdpos" \
+ --http.corsdomain "*" \
+ --ws \
+ --ws.addr "0.0.0.0" \
+ --ws.port 8546 \
+ --ws.api "eth,net,web3,xdpos"
+```
+
+## XDPoS-Specific APIs
+
+The XDPoS consensus engine exposes additional RPC methods:
+
+```javascript
+// Get current masternodes
+> xdpos.getMasternodes()
+
+// Get snapshot at specific block
+> xdpos.getSnapshot(blockNumber)
+
+// Check if address is a masternode
+> xdpos.isValidMasternode(address)
+
+// Get signers for a specific block
+> xdpos.getSigners(blockNumber)
+```
+
+## Troubleshooting
+
+### No Peers
+
+1. Check firewall allows port 30304 (TCP/UDP)
+2. Verify bootnodes are reachable: `nc -vz 81.0.220.137 30304`
+3. Try adding more bootnodes from the network
+
+### Sync Stalled
+
+1. Check disk space: `df -h`
+2. Check memory usage: `free -m`
+3. Restart with `--cache 4096` for more caching
+
+### Genesis Mismatch
+
+If you see "genesis block mismatch" errors:
+```bash
+# Remove old data and reinitialize
+rm -rf ~/.xdc/XDC
+./build/bin/XDC init genesis/xdc_mainnet.json --datadir ~/.xdc
+```
+
+### Block Validation Errors
+
+Check logs for specific errors:
+```bash
+./build/bin/XDC --verbosity 4 ... # Enable debug logging
+```
+
+Common issues:
+- **"unauthorized"**: Block signer not in masternode list
+- **"invalid difficulty"**: Difficulty calculation mismatch
+- **"invalid timestamp"**: Block time too close to parent
+
+## Known Limitations
+
+### Current Implementation Status
+
+1. **Reward Distribution**: Basic implementation - distributes rewards at epoch checkpoints
+2. **Penalty System**: Tracks missed blocks, penalizes inactive masternodes
+3. **Contract Integration**: Hook system in place for validator contract calls
+4. **Double Validation**: Signature verification implemented
+
+### What's Working
+
+- ✅ Basic block validation
+- ✅ Signature recovery
+- ✅ Epoch transitions
+- ✅ Masternode list from checkpoint headers
+- ✅ Difficulty calculation
+- ✅ Block sealing
+
+### Needs Live Network Testing
+
+- ⚠️ Smart contract state sync (0x88 validator contract)
+- ⚠️ Full reward distribution with voter rewards
+- ⚠️ Cross-epoch penalty persistence
+- ⚠️ Network sync with production bootnodes
+
+## Performance Tuning
+
+For production deployments:
+
+```bash
+./build/bin/XDC \
+ --networkid 50 \
+ --datadir /data/xdc \
+ --syncmode full \
+ --cache 8192 \
+ --maxpeers 100 \
+ --txpool.globalslots 16384 \
+ --txpool.globalqueue 4096
+```
+
+## Security Considerations
+
+1. **RPC Access**: Never expose RPC without authentication in production
+2. **Key Storage**: Use hardware wallets or encrypted keystores for masternodes
+3. **Firewall**: Only allow necessary ports (30304 for P2P, 8545/8546 for RPC if needed)
+
+## Resources
+
+- [XDC Network Documentation](https://docs.xdc.org/)
+- [XDPoSChain Reference Implementation](https://github.com/XinFinOrg/XDPoSChain)
+- [XDC Block Explorer](https://explorer.xinfin.network/)
+- [Apothem Faucet](https://faucet.apothem.network/)
+
+## Reporting Issues
+
+If you encounter issues:
+
+1. Enable debug logging: `--verbosity 5`
+2. Capture logs around the error
+3. Note the block number where it failed
+4. Open an issue with logs and system info
diff --git a/consensus/XDPoS/contracts.go b/consensus/XDPoS/contracts.go
new file mode 100644
index 0000000000..6b27ee7f9e
--- /dev/null
+++ b/consensus/XDPoS/contracts.go
@@ -0,0 +1,184 @@
+// Copyright (c) 2018 XDCchain
+// Copyright 2024 The go-ethereum Authors
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see .
+
+package XDPoS
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+)
+
+// XDC System Contract Addresses
+var (
+ // ValidatorContractAddress is the XDPoS validator contract at 0x88
+ // This contract manages masternodes, staking, and voting
+ ValidatorContractAddress = common.HexToAddress("0x0000000000000000000000000000000000000088")
+
+ // BlockSignerContractAddress is the block signer contract at 0x89
+ // This contract tracks which masternodes signed each block
+ BlockSignerContractAddress = common.HexToAddress("0x0000000000000000000000000000000000000089")
+
+ // RandomizeContractAddress is the randomize contract at 0x90
+ // This contract provides VRF for masternode selection
+ RandomizeContractAddress = common.HexToAddress("0x0000000000000000000000000000000000000090")
+)
+
+// Contract Method Signatures (function selectors)
+var (
+ // getCandidates() returns (address[])
+ // Function selector: 0x06a49fce
+ GetCandidatesMethod = []byte{0x06, 0xa4, 0x9f, 0xce}
+
+ // getMasternodes() returns (address[])
+ // Function selector: 0xc7e5e134 (may vary)
+ GetMasternodesMethod = []byte{0xc7, 0xe5, 0xe1, 0x34}
+
+ // getCandidateCap(address) returns (uint256)
+ // Function selector: 0x58e7525f
+ GetCandidateCapMethod = []byte{0x58, 0xe7, 0x52, 0x5f}
+
+ // getVoters(address) returns (address[])
+ // Function selector: 0x2d15cc04
+ GetVotersMethod = []byte{0x2d, 0x15, 0xcc, 0x04}
+
+ // getVoterCap(address, address) returns (uint256)
+ // Function selector: 0x302b6872
+ GetVoterCapMethod = []byte{0x30, 0x2b, 0x68, 0x72}
+
+ // resign(address) - called when masternode resigns
+ // Function selector: 0xae6e43f5
+ ResignMethod = []byte{0xae, 0x6e, 0x43, 0xf5}
+
+ // vote(address) - called when voting for a masternode
+ // Function selector: 0x6dd7d8ea
+ VoteMethod = []byte{0x6d, 0xd7, 0xd8, 0xea}
+
+ // propose(address) - called when proposing a new masternode
+ // Function selector: 0x012679511
+ ProposeMethod = []byte{0x01, 0x26, 0x79, 0x51}
+
+ // Sign method for block signer contract
+ // sign(uint256, bytes32) - 0xe341eaa4
+ SignMethod = []byte{0xe3, 0x41, 0xea, 0xa4}
+
+ // setSecret(bytes32[]) - 0x34d38600
+ SetSecretMethod = []byte{0x34, 0xd3, 0x86, 0x00}
+
+ // setOpening(bytes32[]) - 0xe11f5ba2
+ SetOpeningMethod = []byte{0xe1, 0x1f, 0x5b, 0xa2}
+)
+
+// ContractCallData builds the calldata for a contract method call
+func ContractCallData(method []byte, args ...[]byte) []byte {
+ data := make([]byte, len(method))
+ copy(data, method)
+ for _, arg := range args {
+ data = append(data, arg...)
+ }
+ return data
+}
+
+// AddressToPaddedBytes converts an address to 32-byte padded format for contract calls
+func AddressToPaddedBytes(addr common.Address) []byte {
+ padded := make([]byte, 32)
+ copy(padded[12:], addr[:])
+ return padded
+}
+
+// Uint256ToBytes converts a uint64 to 32-byte big-endian format
+func Uint256ToBytes(val uint64) []byte {
+ result := make([]byte, 32)
+ for i := 31; i >= 0 && val > 0; i-- {
+ result[i] = byte(val & 0xff)
+ val >>= 8
+ }
+ return result
+}
+
+// ExtractAddressesFromReturn extracts addresses from contract return data
+// The return format is: offset (32 bytes) + length (32 bytes) + addresses (20 bytes each, padded to 32)
+func ExtractAddressesFromReturn(data []byte) []common.Address {
+ if len(data) < 64 {
+ return nil
+ }
+
+ // Skip offset (first 32 bytes)
+ // Read length from next 32 bytes
+ lengthStart := 32
+ var length uint64
+ for i := lengthStart; i < lengthStart+32 && i < len(data); i++ {
+ length = (length << 8) | uint64(data[i])
+ }
+
+ if length == 0 || len(data) < 64+int(length)*32 {
+ return nil
+ }
+
+ addresses := make([]common.Address, 0, length)
+ for i := uint64(0); i < length; i++ {
+ start := 64 + i*32 + 12 // Skip padding
+ if start+20 > uint64(len(data)) {
+ break
+ }
+ var addr common.Address
+ copy(addr[:], data[start:start+20])
+ addresses = append(addresses, addr)
+ }
+
+ return addresses
+}
+
+// GetMasternodesCallData returns the calldata for getMasternodes()
+func GetMasternodesCallData() []byte {
+ return GetMasternodesMethod
+}
+
+// GetCandidatesCallData returns the calldata for getCandidates()
+func GetCandidatesCallData() []byte {
+ return GetCandidatesMethod
+}
+
+// SignBlockCallData returns the calldata for sign(blockNumber, blockHash)
+func SignBlockCallData(blockNumber uint64, blockHash common.Hash) []byte {
+ data := make([]byte, 0, 4+32+32)
+ data = append(data, SignMethod...)
+ data = append(data, Uint256ToBytes(blockNumber)...)
+ data = append(data, blockHash[:]...)
+ return data
+}
+
+// ValidatorCandidateInfo represents information about a masternode candidate
+type ValidatorCandidateInfo struct {
+ Address common.Address
+ Cap uint64 // Staked amount
+ Status int // 0 = candidate, 1 = masternode, 2 = resigned
+}
+
+// IsSystemContract checks if an address is a known XDC system contract
+func IsSystemContract(addr common.Address) bool {
+ return addr == ValidatorContractAddress ||
+ addr == BlockSignerContractAddress ||
+ addr == RandomizeContractAddress
+}
+
+// GetValidatorContractAddress returns the validator contract address
+func GetValidatorContractAddress() common.Address {
+ return ValidatorContractAddress
+}
+
+// GetBlockSignerContractAddress returns the block signer contract address
+func GetBlockSignerContractAddress() common.Address {
+ return BlockSignerContractAddress
+}
diff --git a/consensus/XDPoS/penalty.go b/consensus/XDPoS/penalty.go
new file mode 100644
index 0000000000..dcaafdf4b8
--- /dev/null
+++ b/consensus/XDPoS/penalty.go
@@ -0,0 +1,216 @@
+// Copyright (c) 2018 XDCchain
+// Copyright 2024 The go-ethereum Authors
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see .
+
+package XDPoS
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/consensus"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/log"
+)
+
+// PenaltyConfig holds configuration for penalty calculation
+type PenaltyConfig struct {
+ // MinimumBlocksPerEpoch is the minimum number of blocks a masternode must sign
+ // to avoid being penalized
+ MinimumBlocksPerEpoch int64
+
+ // LimitPenaltyEpoch is the number of epochs a penalized masternode remains banned
+ LimitPenaltyEpoch int
+}
+
+// DefaultPenaltyConfig returns the default penalty configuration
+func DefaultPenaltyConfig() *PenaltyConfig {
+ return &PenaltyConfig{
+ MinimumBlocksPerEpoch: MinimunMinerBlockPerEpoch, // 1
+ LimitPenaltyEpoch: LimitPenaltyEpoch, // 4
+ }
+}
+
+// CalculatePenalties determines which masternodes should be penalized
+// Masternodes are penalized if they:
+// - Failed to sign the minimum required blocks in an epoch
+// - Behaved maliciously (double signing, etc.)
+func CalculatePenalties(
+ chain consensus.ChainHeaderReader,
+ epoch uint64,
+ masternodes []common.Address,
+ signCount map[common.Address]int64,
+ config *PenaltyConfig,
+) []common.Address {
+ penalties := make([]common.Address, 0)
+
+ if config == nil {
+ config = DefaultPenaltyConfig()
+ }
+
+ for _, masternode := range masternodes {
+ count, exists := signCount[masternode]
+
+ // Penalize masternodes who didn't sign enough blocks
+ if !exists || count < config.MinimumBlocksPerEpoch {
+ penalties = append(penalties, masternode)
+ log.Info("Masternode penalized for insufficient signing",
+ "address", masternode.Hex(),
+ "signCount", count,
+ "minimum", config.MinimumBlocksPerEpoch,
+ "epoch", epoch)
+ }
+ }
+
+ return penalties
+}
+
+// CreateDefaultHookPenalty creates a default penalty hook function
+// This calculates penalties based on block signing activity
+func (c *XDPoS) CreateDefaultHookPenalty() func(chain consensus.ChainHeaderReader, blockNumberEpoch uint64) ([]common.Address, error) {
+ return func(chain consensus.ChainHeaderReader, blockNumberEpoch uint64) ([]common.Address, error) {
+ epoch := c.config.Epoch
+ if blockNumberEpoch == 0 || epoch == 0 {
+ return []common.Address{}, nil
+ }
+
+ // Calculate the start and end blocks of the previous epoch
+ epochStart := blockNumberEpoch - epoch
+ if epochStart > blockNumberEpoch {
+ // Overflow protection
+ return []common.Address{}, nil
+ }
+
+ // Get checkpoint header for this epoch
+ checkpointHeader := chain.GetHeaderByNumber(epochStart)
+ if checkpointHeader == nil {
+ log.Warn("Could not find checkpoint header for penalty calculation",
+ "epochStart", epochStart)
+ return []common.Address{}, nil
+ }
+
+ // Get masternodes for this epoch
+ masternodes := c.GetMasternodesFromCheckpointHeader(checkpointHeader, epochStart, epoch)
+ if len(masternodes) == 0 {
+ return []common.Address{}, nil
+ }
+
+ // Count how many blocks each masternode signed
+ signCount := make(map[common.Address]int64)
+
+ for blockNum := epochStart + 1; blockNum < blockNumberEpoch; blockNum++ {
+ header := chain.GetHeaderByNumber(blockNum)
+ if header == nil {
+ continue
+ }
+
+ signer, err := c.RecoverSigner(header)
+ if err != nil {
+ log.Debug("Could not recover signer for penalty calculation",
+ "block", blockNum, "error", err)
+ continue
+ }
+
+ signCount[signer]++
+ }
+
+ // Calculate penalties
+ penalties := CalculatePenalties(chain, blockNumberEpoch/epoch, masternodes, signCount, DefaultPenaltyConfig())
+
+ return penalties, nil
+ }
+}
+
+// CreateDefaultHookPenaltyTIPSigning creates a penalty hook for TIP signing
+// This is an enhanced penalty calculation that includes signature validation
+func (c *XDPoS) CreateDefaultHookPenaltyTIPSigning() func(chain consensus.ChainHeaderReader, header *types.Header, candidates []common.Address) ([]common.Address, error) {
+ return func(chain consensus.ChainHeaderReader, header *types.Header, candidates []common.Address) ([]common.Address, error) {
+ number := header.Number.Uint64()
+ epoch := c.config.Epoch
+
+ if number == 0 || epoch == 0 {
+ return []common.Address{}, nil
+ }
+
+ // Get the epoch start
+ epochStart := number - epoch
+ if epochStart > number {
+ return []common.Address{}, nil
+ }
+
+ // Build a map of valid candidates
+ candidateMap := make(map[common.Address]bool)
+ for _, c := range candidates {
+ candidateMap[c] = true
+ }
+
+ // Count signatures
+ signCount := make(map[common.Address]int64)
+
+ for blockNum := epochStart + 1; blockNum < number; blockNum++ {
+ blockHeader := chain.GetHeaderByNumber(blockNum)
+ if blockHeader == nil {
+ continue
+ }
+
+ signer, err := c.RecoverSigner(blockHeader)
+ if err != nil {
+ continue
+ }
+
+ // Only count signatures from valid candidates
+ if candidateMap[signer] {
+ signCount[signer]++
+ }
+ }
+
+ // Calculate penalties for candidates who didn't sign enough
+ penalties := make([]common.Address, 0)
+ minBlocks := int64(MinimunMinerBlockPerEpoch)
+
+ for _, candidate := range candidates {
+ if signCount[candidate] < minBlocks {
+ penalties = append(penalties, candidate)
+ log.Info("Candidate penalized (TIP signing)",
+ "address", candidate.Hex(),
+ "signCount", signCount[candidate],
+ "minimum", minBlocks,
+ "block", number)
+ }
+ }
+
+ return penalties, nil
+ }
+}
+
+// ExtractPenaltiesFromHeader extracts penalty addresses from a block header
+func ExtractPenaltiesFromHeader(header *types.Header) []common.Address {
+ // In XDC, penalties are stored in the Penalties field of the header
+ // For compatibility with standard go-ethereum, we might need to handle this differently
+ // Currently returning empty as standard headers don't have this field
+
+ // If we had access to header.Penalties:
+ // return extractAddressFromBytes(header.Penalties)
+
+ return []common.Address{}
+}
+
+// IsPenalized checks if an address is in the penalty list
+func IsPenalized(address common.Address, penalties []common.Address) bool {
+ for _, penalty := range penalties {
+ if penalty == address {
+ return true
+ }
+ }
+ return false
+}
diff --git a/consensus/XDPoS/reward.go b/consensus/XDPoS/reward.go
new file mode 100644
index 0000000000..f3dfee8b61
--- /dev/null
+++ b/consensus/XDPoS/reward.go
@@ -0,0 +1,210 @@
+// Copyright (c) 2018 XDCchain
+// Copyright 2024 The go-ethereum Authors
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see .
+
+package XDPoS
+
+import (
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/consensus"
+ "github.com/ethereum/go-ethereum/core/state"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/holiman/uint256"
+)
+
+// RewardConfig holds the configuration for block rewards
+type RewardConfig struct {
+ // BlockReward is the base block reward in wei
+ BlockReward *big.Int
+ // MasterPercent is the percentage of reward going to masternodes (90%)
+ MasterPercent int64
+ // VoterPercent is the percentage of reward going to voters (0% in current implementation)
+ VoterPercent int64
+ // FoundationPercent is the percentage of reward going to foundation (10%)
+ FoundationPercent int64
+ // FoundationWallet is the address receiving foundation rewards
+ FoundationWallet common.Address
+}
+
+// DefaultRewardConfig returns the default XDC reward configuration
+// Block reward: 5000 XDC per epoch (distributed among masternodes)
+// Note: The actual calculation is more complex in production
+func DefaultRewardConfig(foundationWallet common.Address) *RewardConfig {
+ // 5000 XDC = 5000 * 10^18 wei
+ blockReward := new(big.Int).Mul(big.NewInt(5000), big.NewInt(1e18))
+
+ return &RewardConfig{
+ BlockReward: blockReward,
+ MasterPercent: RewardMasterPercent, // 90
+ VoterPercent: RewardVoterPercent, // 0
+ FoundationPercent: RewardFoundationPercent, // 10
+ FoundationWallet: foundationWallet,
+ }
+}
+
+// CalculateRewards calculates the rewards for masternodes at checkpoint blocks
+// This implements the XDC reward distribution mechanism:
+// - 90% to masternodes who signed blocks
+// - 10% to foundation wallet
+// - 0% to voters (handled separately by voter contract)
+func CalculateRewards(
+ chain consensus.ChainHeaderReader,
+ state *state.StateDB,
+ header *types.Header,
+ config *RewardConfig,
+ signers []common.Address,
+ signCount map[common.Address]int64,
+) (map[string]interface{}, error) {
+ rewards := make(map[string]interface{})
+ number := header.Number.Uint64()
+
+ if config == nil || config.BlockReward == nil || config.BlockReward.Sign() <= 0 {
+ log.Debug("No reward configured", "number", number)
+ return rewards, nil
+ }
+
+ // Calculate total signs in this epoch
+ var totalSigns int64
+ for _, count := range signCount {
+ totalSigns += count
+ }
+
+ if totalSigns == 0 {
+ log.Warn("No signatures found for reward calculation", "number", number)
+ return rewards, nil
+ }
+
+ // Calculate masternode portion (90%)
+ masternodeReward := new(big.Int).Mul(config.BlockReward, big.NewInt(config.MasterPercent))
+ masternodeReward.Div(masternodeReward, big.NewInt(100))
+
+ // Calculate foundation portion (10%)
+ foundationReward := new(big.Int).Mul(config.BlockReward, big.NewInt(config.FoundationPercent))
+ foundationReward.Div(foundationReward, big.NewInt(100))
+
+ // Distribute rewards to masternodes based on their signing activity
+ masternodeRewards := make(map[common.Address]*big.Int)
+ totalDistributed := big.NewInt(0)
+
+ for addr, count := range signCount {
+ if count > 0 {
+ // Reward proportional to number of blocks signed
+ reward := new(big.Int).Mul(masternodeReward, big.NewInt(count))
+ reward.Div(reward, big.NewInt(totalSigns))
+
+ if reward.Sign() > 0 {
+ masternodeRewards[addr] = reward
+ totalDistributed.Add(totalDistributed, reward)
+
+ // Add reward to state (convert big.Int to uint256.Int)
+ rewardU256, _ := uint256.FromBig(reward)
+ state.AddBalance(addr, rewardU256, tracing.BalanceIncreaseRewardMineBlock)
+ log.Debug("Masternode reward",
+ "address", addr.Hex(),
+ "reward", reward.String(),
+ "signs", count,
+ "block", number)
+ }
+ }
+ }
+
+ // Send foundation reward
+ if foundationReward.Sign() > 0 && config.FoundationWallet != (common.Address{}) {
+ foundationRewardU256, _ := uint256.FromBig(foundationReward)
+ state.AddBalance(config.FoundationWallet, foundationRewardU256, tracing.BalanceIncreaseRewardMineBlock)
+ log.Debug("Foundation reward",
+ "address", config.FoundationWallet.Hex(),
+ "reward", foundationReward.String(),
+ "block", number)
+ }
+
+ // Build rewards map for logging/storage
+ rewards["block"] = number
+ rewards["totalReward"] = config.BlockReward.String()
+ rewards["masternodeReward"] = masternodeReward.String()
+ rewards["foundationReward"] = foundationReward.String()
+ rewards["totalSigns"] = totalSigns
+
+ masternodeRewardStrings := make(map[string]string)
+ for addr, reward := range masternodeRewards {
+ masternodeRewardStrings[addr.Hex()] = reward.String()
+ }
+ rewards["masternodes"] = masternodeRewardStrings
+
+ log.Info("Rewards distributed",
+ "block", number,
+ "totalReward", config.BlockReward.String(),
+ "masternodes", len(masternodeRewards),
+ "foundation", foundationReward.String())
+
+ return rewards, nil
+}
+
+// CreateDefaultHookReward creates a default reward hook function
+// This can be used to set up the HookReward function in the XDPoS engine
+func (c *XDPoS) CreateDefaultHookReward() func(chain consensus.ChainHeaderReader, state *state.StateDB, header *types.Header) (map[string]interface{}, error) {
+ return func(chain consensus.ChainHeaderReader, state *state.StateDB, header *types.Header) (map[string]interface{}, error) {
+ number := header.Number.Uint64()
+ epoch := c.config.Epoch
+
+ // Get the foundation wallet from config
+ foundationWallet := common.Address{}
+ if c.config.FoudationWalletAddr != (common.Address{}) {
+ foundationWallet = c.config.FoudationWalletAddr
+ }
+
+ rewardConfig := DefaultRewardConfig(foundationWallet)
+
+ // Get masternodes for this epoch
+ masternodes := c.GetMasternodes(chain, header)
+ if len(masternodes) == 0 {
+ log.Warn("No masternodes found for reward calculation", "number", number)
+ return make(map[string]interface{}), nil
+ }
+
+ // Count signatures in the epoch
+ // In a full implementation, this would scan the blocks in the epoch
+ // and count how many times each masternode signed
+ signCount := make(map[common.Address]int64)
+
+ startBlock := number - (number % epoch)
+ if startBlock == 0 {
+ startBlock = 1
+ }
+
+ // Simplified: give each masternode equal weight
+ // In production, this should count actual block signatures
+ for _, mn := range masternodes {
+ signCount[mn] = 1
+ }
+
+ // Scan recent blocks to count actual signatures
+ for blockNum := startBlock; blockNum < number; blockNum++ {
+ blockHeader := chain.GetHeaderByNumber(blockNum)
+ if blockHeader != nil {
+ signer, err := c.RecoverSigner(blockHeader)
+ if err == nil {
+ signCount[signer]++
+ }
+ }
+ }
+
+ return CalculateRewards(chain, state, header, rewardConfig, masternodes, signCount)
+ }
+}
diff --git a/genesis/xdc_apothem.json b/genesis/xdc_apothem.json
new file mode 100644
index 0000000000..07a5bc931b
--- /dev/null
+++ b/genesis/xdc_apothem.json
@@ -0,0 +1,40 @@
+{
+ "config": {
+ "chainId": 51,
+ "homesteadBlock": 0,
+ "eip150Block": 0,
+ "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "eip155Block": 0,
+ "eip158Block": 0,
+ "byzantiumBlock": 0,
+ "XDPoS": {
+ "period": 2,
+ "epoch": 900,
+ "reward": 5000,
+ "rewardCheckpoint": 900,
+ "gap": 450,
+ "foudationWalletAddr": "0x746f746f726f0000000000000000000000000000"
+ }
+ },
+ "nonce": "0x0",
+ "timestamp": "0x5e4c3000",
+ "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000d64e5b8d8f33e2f86e78e0f52d088bff0af44ccb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "gasLimit": "0x47b760",
+ "difficulty": "0x1",
+ "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase": "0x0000000000000000000000000000000000000000",
+ "alloc": {
+ "0000000000000000000000000000000000000088": {
+ "comment": "XDPoS Validator Contract",
+ "balance": "0x0"
+ },
+ "0000000000000000000000000000000000000089": {
+ "comment": "Block Signer Contract",
+ "balance": "0x0"
+ },
+ "d64e5b8d8f33e2f86e78e0f52d088bff0af44ccb": {
+ "comment": "Apothem testnet initial masternode",
+ "balance": "0x84595161401484a000000"
+ }
+ }
+}
diff --git a/genesis/xdc_mainnet.json b/genesis/xdc_mainnet.json
new file mode 100644
index 0000000000..533590dbe5
--- /dev/null
+++ b/genesis/xdc_mainnet.json
@@ -0,0 +1,52 @@
+{
+ "config": {
+ "chainId": 50,
+ "homesteadBlock": 1,
+ "eip150Block": 2,
+ "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "eip155Block": 3,
+ "eip158Block": 3,
+ "byzantiumBlock": 4,
+ "XDPoS": {
+ "period": 2,
+ "epoch": 900,
+ "reward": 5000,
+ "rewardCheckpoint": 900,
+ "gap": 450,
+ "foudationWalletAddr": "0x92a289fe95a85c53b8d0d113cbaef0c1ec98ac65"
+ }
+ },
+ "nonce": "0x0",
+ "timestamp": "0x5cefae27",
+ "extraData": "0x000000000000000000000000000000000000000000000000000000000000000025c65b4b379ac37cf78357c4915f73677022eaffc7d49d0a2cf198deebd6ce581af465944ec8b2bbcfccdea1006a5cfa7d9484b5b293b46964c265c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "gasLimit": "0x47b760",
+ "difficulty": "0x1",
+ "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "coinbase": "0x0000000000000000000000000000000000000000",
+ "alloc": {
+ "0000000000000000000000000000000000000088": {
+ "comment": "XDPoS Validator Contract - manages masternodes, staking, and voting",
+ "balance": "0x18d0bf423c03d8de000000"
+ },
+ "0000000000000000000000000000000000000089": {
+ "comment": "Block Signer Contract - tracks block signers",
+ "balance": "0x0"
+ },
+ "0000000000000000000000000000000000000090": {
+ "comment": "Randomize Contract - VRF for masternode selection",
+ "balance": "0x0"
+ },
+ "25c65b4b379ac37cf78357c4915f73677022eaff": {
+ "comment": "Initial Masternode 1",
+ "balance": "0x84595161401484a000000"
+ },
+ "c7d49d0a2cf198deebd6ce581af465944ec8b2bb": {
+ "comment": "Initial Masternode 2",
+ "balance": "0x84595161401484a000000"
+ },
+ "cfccdea1006a5cfa7d9484b5b293b46964c265c0": {
+ "comment": "Initial Masternode 3",
+ "balance": "0x84595161401484a000000"
+ }
+ }
+}
diff --git a/params/bootnodes.go b/params/bootnodes.go
index 28e3395540..8abee9c366 100644
--- a/params/bootnodes.go
+++ b/params/bootnodes.go
@@ -79,6 +79,37 @@ var V5Bootnodes = []string{
"enr:-LK4QKWrXTpV9T78hNG6s8AM6IO4XH9kFT91uZtFg1GcsJ6dKovDOr1jtAAFPnS2lvNltkOGA9k29BUN7lFh_sjuc9QBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhANAdd-Jc2VjcDI1NmsxoQLQa6ai7y9PMN5hpLe5HmiJSlYzMuzP7ZhwRiwHvqNXdoN0Y3CCI4yDdWRwgiOM", // 3.64.117.223 | aws-eu-central-1-frankfurt}
}
+// XDCMainnetBootnodes are the enode URLs of the P2P bootstrap nodes running on
+// the XDC mainnet (Chain ID: 50).
+var XDCMainnetBootnodes = []string{
+ // XDPoSChain Bootnodes Mainnet
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@81.0.220.137:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@5.189.144.192:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@154.53.42.5:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@85.239.236.17:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@85.239.236.16:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@161.97.121.140:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@209.126.1.25:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@209.126.11.52:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@209.126.11.108:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@209.126.9.230:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@109.123.242.198:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@209.126.2.33:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@161.97.131.145:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@161.97.172.27:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@109.123.242.118:30304",
+ "enode://91e59fa1b034ae35e9f4e8a99cc6621f09d74e76a6220abb6c93b29ed41a9e1fc4e5b70e2c5fc43f883cffbdcd6f4f6cbc1d23af077f28c2aecc22403355d4b1@66.94.97.241:30304",
+}
+
+// XDCApothemBootnodes are the enode URLs of the P2P bootstrap nodes running on
+// the XDC Apothem testnet (Chain ID: 51).
+var XDCApothemBootnodes = []string{
+ // Apothem testnet bootnodes
+ "enode://e05b6b3b2c116e3d9d88e1e71b1c7a5d6a09f8d6e8b1e7c6d5a4b3c2d1e0f9a8@157.245.233.39:30303",
+ "enode://f3e2d1c0b9a8d7c6e5f4e3d2c1b0a9f8e7d6c5b4a3e2d1c0f9e8d7c6b5a4c3d2@68.183.235.197:30303",
+ "enode://a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2@165.227.183.186:30303",
+}
+
const dnsPrefix = "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@"
// KnownDNSNetwork returns the address of a public DNS-based node list for the given
@@ -95,6 +126,10 @@ func KnownDNSNetwork(genesis common.Hash, protocol string) string {
net = "holesky"
case HoodiGenesisHash:
net = "hoodi"
+ case XDCMainnetGenesisHash:
+ return "" // XDC doesn't use DNS-based discovery
+ case XDCApothemGenesisHash:
+ return "" // XDC doesn't use DNS-based discovery
default:
return ""
}