Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,844 changes: 2,032 additions & 1,812 deletions consensus/parlia/abi.go

Large diffs are not rendered by default.

224 changes: 224 additions & 0 deletions consensus/parlia/stakehub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
package parlia

import (
"context"
"fmt"
"math"
"math/big"

"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/systemcontracts"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/rpc"
)

// GetValidators retrieves validators from the StakeHubContract
// It returns operator addresses, credit addresses, and total length of validators
func (p *Parlia) GetValidators(blockNumber uint64, offset, limit *big.Int) ([]common.Address, []common.Address, *big.Int, error) {

This comment was marked as resolved.

log.Debug("Getting validators", "block", blockNumber, "offset", offset, "limit", limit)

// Create the call data for getValidators
data, err := p.stakeHubABI.Pack("getValidators", offset, limit)
if err != nil {
log.Error("Failed to pack getValidators", "error", err)
return nil, nil, nil, fmt.Errorf("failed to pack getValidators: %v", err)
}

// Make the call
blockNr := rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(blockNumber))
msgData := (hexutil.Bytes)(data)
toAddress := common.HexToAddress(systemcontracts.StakeHubContract)
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))

log.Debug("Calling getValidators", "block", blockNumber, "to", toAddress)
result, err := p.ethAPI.Call(context.Background(), ethapi.TransactionArgs{
Gas: &gas,
To: &toAddress,
Data: &msgData,
}, &blockNr, nil, nil)
if err != nil {
log.Error("Failed to call getValidators", "error", err)
return nil, nil, nil, fmt.Errorf("failed to call getValidators: %v", err)
}

// Unpack the result
var operatorAddrs []common.Address
var creditAddrs []common.Address
var totalLength *big.Int
if err := p.stakeHubABI.UnpackIntoInterface(&[]interface{}{&operatorAddrs, &creditAddrs, &totalLength}, "getValidators", result); err != nil {
log.Error("Failed to unpack getValidators result", "error", err)
return nil, nil, nil, fmt.Errorf("failed to unpack getValidators result: %v", err)
}

log.Debug("Successfully retrieved validators", "operators", len(operatorAddrs), "credits", len(creditAddrs), "total", totalLength)
return operatorAddrs, creditAddrs, totalLength, nil
}

// getNodeIDsForValidators retrieves node IDs for the given validators
// It returns a map of consensus addresses to their node IDs
func (p *Parlia) getNodeIDsForValidators(blockNumber uint64, validatorsToQuery []common.Address) (map[common.Address][]enode.ID, error) {
log.Debug("Listing node IDs for validators", "block", blockNumber, "validators", len(validatorsToQuery))

// Create the call data for getNodeIDs
data, err := p.stakeHubABI.Pack("getNodeIDs", validatorsToQuery)
if err != nil {
log.Error("Failed to pack getNodeIDs", "error", err)
return nil, fmt.Errorf("failed to pack getNodeIDs: %v", err)
}

// Make the call
blockNr := rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(blockNumber))
msgData := (hexutil.Bytes)(data)
toAddress := common.HexToAddress(systemcontracts.StakeHubContract)
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))

log.Debug("Calling getNodeIDs", "block", blockNumber, "to", toAddress)
result, err := p.ethAPI.Call(context.Background(), ethapi.TransactionArgs{
Gas: &gas,
To: &toAddress,
Data: &msgData,
}, &blockNr, nil, nil)
if err != nil {
log.Error("Failed to call getNodeIDs", "error", err)
return nil, fmt.Errorf("failed to call getNodeIDs: %v", err)
}

// Unpack the result
var consensusAddresses []common.Address
var nodeIDsList [][]enode.ID
if err := p.stakeHubABI.UnpackIntoInterface(&[]interface{}{&consensusAddresses, &nodeIDsList}, "getNodeIDs", result); err != nil {
log.Error("Failed to unpack getNodeIDs result", "error", err)
return nil, fmt.Errorf("failed to unpack getNodeIDs result: %v", err)
}

// Create a map of addresses to node IDs
addressToNodeIDs := make(map[common.Address][]enode.ID)
for i, addr := range consensusAddresses {
if i < len(nodeIDsList) {
addressToNodeIDs[addr] = nodeIDsList[i]
}
}

log.Debug("Successfully retrieved node IDs", "addresses", len(addressToNodeIDs))
return addressToNodeIDs, nil
}

// GetNodeIDs returns a flattened array of all node IDs for current validators
func (p *Parlia) GetNodeIDs() ([]enode.ID, error) {
// Get latest block number
block := p.ethAPI.BlockNumber()
log.Debug("Getting all node IDs", "block", block)

// Call GetValidators with latest block number
operatorAddrs, _, _, err := p.GetValidators(uint64(block), big.NewInt(0), big.NewInt(1000))
if err != nil {
log.Error("Failed to get validators", "error", err)
return nil, fmt.Errorf("failed to get validators: %v", err)
}
log.Debug("Retrieved validators", "count", len(operatorAddrs))

// Get node IDs for validators
nodeIDs, err := p.getNodeIDsForValidators(uint64(block), operatorAddrs)
if err != nil {
log.Error("Failed to get node IDs", "error", err)
return nil, fmt.Errorf("failed to get node IDs: %v", err)
}
log.Debug("Retrieved node IDs map", "addresses", len(nodeIDs))

// Flatten the array of arrays into a single array
flatNodeIDs := make([]enode.ID, 0)
for addr, nodeIDArray := range nodeIDs {
flatNodeIDs = append(flatNodeIDs, nodeIDArray...)
log.Debug("Processing node IDs", "address", addr, "count", len(nodeIDArray))
}

log.Debug("Successfully flattened node IDs", "total", len(flatNodeIDs))
return flatNodeIDs, nil
}

// AddNodeIDs creates a signed transaction to add node IDs to the StakeHub contract
func (p *Parlia) AddNodeIDs(nodeIDs []enode.ID, nonce uint64) (*types.Transaction, error) {
log.Debug("Adding node IDs", "count", len(nodeIDs), "nonce", nonce)

p.lock.RLock()
signTxFn := p.signTxFn
val := p.val
p.lock.RUnlock()

if signTxFn == nil {
log.Error("Signing function not set")
return nil, fmt.Errorf("signing function not set, call Authorize first")
}

// Create the call data for addNodeIDs
data, err := p.stakeHubABI.Pack("addNodeIDs", nodeIDs)
if err != nil {
log.Error("Failed to pack addNodeIDs", "error", err)
return nil, fmt.Errorf("failed to pack addNodeIDs: %v", err)
}

to := common.HexToAddress(systemcontracts.StakeHubContract)
hexData := hexutil.Bytes(data)
hexNonce := hexutil.Uint64(nonce)
gas, err := p.ethAPI.EstimateGas(context.Background(), ethapi.TransactionArgs{
Copy link

Copilot AI Apr 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider providing a context with a timeout for the gas estimation call to avoid potential indefinite hangs.

Suggested change
gas, err := p.ethAPI.EstimateGas(context.Background(), ethapi.TransactionArgs{
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
gas, err := p.ethAPI.EstimateGas(ctx, ethapi.TransactionArgs{

Copilot uses AI. Check for mistakes.
From: &val,
To: &to,
Nonce: &hexNonce,
Data: &hexData,
}, nil, nil, nil)
if err != nil {
log.Error("Failed to estimate gas", "error", err)
return nil, fmt.Errorf("failed to estimate gas: %v", err)
}

// Create the transaction
tx := types.NewTransaction(
nonce,
common.HexToAddress(systemcontracts.StakeHubContract),
common.Big0,
uint64(gas),
big.NewInt(1000000000),
data,
)

// Sign the transaction with the node's private key
log.Debug("Signing transaction", "validator", val)
signedTx, err := signTxFn(accounts.Account{Address: val}, tx, p.chainConfig.ChainID)
if err != nil {
log.Error("Failed to sign transaction", "error", err)
return nil, fmt.Errorf("failed to sign transaction: %v", err)
}

log.Debug("Successfully created signed transaction", "hash", signedTx.Hash())
return signedTx, nil
}

// GetNodeIDsMap returns a map of consensus addresses to their node IDs for all current validators
func (p *Parlia) GetNodeIDsMap() (map[common.Address][]enode.ID, error) {
// Get latest block number
block := p.ethAPI.BlockNumber()
log.Debug("Getting node IDs map", "block", block)

// Call GetValidators with latest block number
operatorAddrs, _, _, err := p.GetValidators(uint64(block), big.NewInt(0), big.NewInt(1000))
if err != nil {
log.Error("Failed to get validators", "error", err)
return nil, fmt.Errorf("failed to get validators: %v", err)
}
log.Debug("Retrieved validators", "count", len(operatorAddrs))

// Get node IDs for validators
nodeIDsMap, err := p.getNodeIDsForValidators(uint64(block), operatorAddrs)
if err != nil {
log.Error("Failed to get node IDs", "error", err)
return nil, fmt.Errorf("failed to get node IDs: %v", err)
}
log.Debug("Retrieved node IDs map", "addresses", len(nodeIDsMap))

return nodeIDsMap, nil
}
1 change: 1 addition & 0 deletions core/systemcontracts/maxwell/chapel/StakeHubContract

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions core/systemcontracts/maxwell/mainnet/StakeHubContract

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions core/systemcontracts/maxwell/rialto/StakeHubContract

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions core/systemcontracts/maxwell/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package maxwell

import _ "embed"

// contract codes for Mainnet upgrade
var (
//go:embed mainnet/StakeHubContract
MainnetStakeHubContract string
)

// contract codes for Chapel upgrade
var (
//go:embed chapel/StakeHubContract
ChapelStakeHubContract string
)

// contract codes for Rialto upgrade
var (
//go:embed rialto/StakeHubContract
RialtoStakeHubContract string
)
40 changes: 40 additions & 0 deletions core/systemcontracts/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/ethereum/go-ethereum/core/systemcontracts/kepler"
"github.com/ethereum/go-ethereum/core/systemcontracts/lorentz"
"github.com/ethereum/go-ethereum/core/systemcontracts/luban"
"github.com/ethereum/go-ethereum/core/systemcontracts/maxwell"
"github.com/ethereum/go-ethereum/core/systemcontracts/mirror"
"github.com/ethereum/go-ethereum/core/systemcontracts/moran"
"github.com/ethereum/go-ethereum/core/systemcontracts/niels"
Expand Down Expand Up @@ -89,6 +90,8 @@ var (
pascalUpgrade = make(map[string]*Upgrade)

lorentzUpgrade = make(map[string]*Upgrade)

maxwellUpgrade = make(map[string]*Upgrade)
)

func init() {
Expand Down Expand Up @@ -994,6 +997,39 @@ func init() {
},
},
}

maxwellUpgrade[mainNet] = &Upgrade{
UpgradeName: "maxwell",
Configs: []*UpgradeConfig{
{
ContractAddr: common.HexToAddress(StakeHubContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/19bfe7200029b41d0820efcc6feed6df84a96340",
Code: maxwell.MainnetStakeHubContract,
},
},
}

maxwellUpgrade[chapelNet] = &Upgrade{
UpgradeName: "maxwell",
Configs: []*UpgradeConfig{
{
ContractAddr: common.HexToAddress(StakeHubContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/19bfe7200029b41d0820efcc6feed6df84a96340",
Code: maxwell.ChapelStakeHubContract,
},
},
}

maxwellUpgrade[rialtoNet] = &Upgrade{
UpgradeName: "maxwell",
Configs: []*UpgradeConfig{
{
ContractAddr: common.HexToAddress(StakeHubContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/19bfe7200029b41d0820efcc6feed6df84a96340",
Code: maxwell.RialtoStakeHubContract,
},
},
}
}

func TryUpdateBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, lastBlockTime uint64, blockTime uint64, statedb vm.StateDB, atBlockBegin bool) {
Expand Down Expand Up @@ -1105,6 +1141,10 @@ func upgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.I
applySystemContractUpgrade(lorentzUpgrade[network], blockNumber, statedb, logger)
}

if config.IsOnMaxwell(blockNumber, lastBlockTime, blockTime) {
applySystemContractUpgrade(maxwellUpgrade[network], blockNumber, statedb, logger)
}

/*
apply other upgrades
*/
Expand Down
Loading