Skip to content
Draft
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
20 changes: 12 additions & 8 deletions consensus/posv/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,13 @@ type API struct {
chain consensus.ChainHeaderReader
posv *Posv
}

type NetworkInformation struct {
NetworkId *big.Int
TomoValidatorAddress common.Address
RelayerRegistrationAddress common.Address
TomoXListingAddress common.Address
TomoZAddress common.Address
LendingAddress common.Address
NetworkId *big.Int
ValidatorContract common.Address
RelayerContract common.Address
TomoXContract common.Address
VRC25Contract common.Address
LendingContract common.Address
}

// GetSnapshot retrieves the state snapshot at a given block.
Expand Down Expand Up @@ -98,10 +97,15 @@ func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) {
return snap.GetSigners(), nil
}

// [TO-DO] return nil for network information. --- IGNORE ---
func (api *API) NetworkInformation() NetworkInformation {
api.posv.lock.RLock()
defer api.posv.lock.RUnlock()
info := NetworkInformation{}
info.NetworkId = api.chain.Config().ChainID
info.ValidatorContract = api.chain.Config().Viction.ValidatorContract
info.LendingContract = api.chain.Config().Viction.LendingContract
info.RelayerContract = api.chain.Config().Viction.RelayerContract
info.TomoXContract = api.chain.Config().Viction.TomoXContract
info.VRC25Contract = api.chain.Config().Viction.VRC25Contract
return info
}
13 changes: 13 additions & 0 deletions consensus/posv/posv_extend.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,16 @@ func (c *Posv) GetSignDataForBlock(config *params.ChainConfig, vicConfig *params
c.BlockSigners.Add(blockHash, signers)
return signers, nil
}

// GetSignersAtHash returns validator signers from snapshot at a given block hash.
func (c *Posv) GetSignersAtHash(chain consensus.ChainHeaderReader, hash common.Hash) ([]common.Address, error) {
header := chain.GetHeaderByHash(hash)
if header == nil {
return nil, errUnknownBlock
}
snap, err := c.snapshot(chain, header.Number.Uint64(), header.Hash(), nil)
if err != nil {
return nil, err
}
return snap.GetSigners(), nil
}
177 changes: 177 additions & 0 deletions eth/api_backend_viction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// Copyright 2026 The Vic-geth Authors
package eth

import (
"errors"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/posv"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rpc"
)

func (s *EthAPIBackend) GetRewardByHash(hash common.Hash) (*posv.EpochReward, error) {
header := s.eth.blockchain.GetHeaderByHash(hash)
if header == nil || header.Number.Uint64()%s.eth.blockchain.Config().Posv.Epoch != 0 {
return nil, errors.New("header is not a checkpoint block")
}
engine := s.Engine().(*posv.Posv)
statedb, err := s.eth.blockchain.StateAt(header.Root)
if err != nil {
log.Info("Failed to get state at", "hash", hash, "error", err)
return nil, err
}
epochReward, err := s.eth.PosvGetEpochReward(
engine,
s.eth.blockchain.Config(),
s.eth.blockchain.Config().Posv,
s.eth.blockchain.Config().Viction,
header,
s.eth.blockchain,
statedb,
log.New(),
)
if err != nil {
return nil, err
}
if epochReward == nil {
return nil, errors.New("epoch reward is nil")
}
return epochReward, nil

}

func (s *EthAPIBackend) GetAttestorsPairsByHash(hash common.Hash) (map[common.Address]common.Address, error) {
posvConfig := s.eth.blockchain.Config().Posv
header := s.eth.blockchain.GetHeaderByHash(hash)
if header == nil {
return nil, errors.New("header not found")
}
checkpointHeader := posv.GetCheckpointHeader(posvConfig, header, s.eth.blockchain, nil)
if checkpointHeader == nil {
return nil, errors.New("checkpoint header not found")
}
engine, ok := s.Engine().(*posv.Posv)
if !ok {
return nil, errors.New("engine is not a posv engine")
}
pairs, _, err := s.eth.PosvGetCreatorAttestorPairs(engine, s.eth.blockchain.Config(), header, checkpointHeader)
return pairs, err
}

func (s *EthAPIBackend) GetAttestorsPairsByNumber(number rpc.BlockNumber) (map[common.Address]common.Address, error) {
var blockNumber uint64
switch number {
case rpc.LatestBlockNumber:
blockNumber = s.CurrentBlock().NumberU64()
case rpc.PendingBlockNumber:
return nil, errors.New("pending block number is not supported")
default:
if number < 0 {
return nil, errors.New("invalid block number")
}
blockNumber = uint64(number)
}

posvConfig := s.eth.blockchain.Config().Posv
header := s.eth.blockchain.GetHeaderByNumber(blockNumber)
if header == nil {
return nil, errors.New("header not found")
}
checkpointHeader := posv.GetCheckpointHeader(posvConfig, header, s.eth.blockchain, nil)
if checkpointHeader == nil {
return nil, errors.New("checkpoint header not found")
}
engine, ok := s.Engine().(*posv.Posv)
if !ok {
return nil, errors.New("engine is not a posv engine")
}
pairs, _, err := s.eth.PosvGetCreatorAttestorPairs(engine, s.eth.blockchain.Config(), header, checkpointHeader)
return pairs, err
}

func (s *EthAPIBackend) GetAttestorsByHashAtCheckPoint(hash common.Hash) ([]int64, error) {
header := s.eth.blockchain.GetHeaderByHash(hash)
if header == nil || header.Number.Uint64()%s.eth.blockchain.Config().Posv.Epoch != 0 {
return nil, errors.New("header is not a checkpoint block")
}
_, ok := s.Engine().(*posv.Posv)
if !ok {
return nil, errors.New("engine is not a posv engine")
}
validators := posv.ExtractValidatorsFromCheckpointHeader(header)
attestors, err := s.eth.PosvGetAttestors(s.eth.blockchain.Config().Viction, header, validators)
return attestors, err
}

func (s *EthAPIBackend) GetAttestorsByNumberAtCheckPoint(number rpc.BlockNumber) ([]int64, error) {
var blockNumber uint64
switch number {
case rpc.LatestBlockNumber:
blockNumber = s.CurrentBlock().NumberU64()
case rpc.PendingBlockNumber:
return nil, errors.New("pending block number is not supported")
default:
if number < 0 {
return nil, errors.New("invalid block number")
}
blockNumber = uint64(number)
}
header := s.eth.blockchain.GetHeaderByNumber(blockNumber)
if header == nil || header.Number.Uint64()%s.eth.blockchain.Config().Posv.Epoch != 0 {
return nil, errors.New("header not found")
}
_, ok := s.Engine().(*posv.Posv)
if !ok {
return nil, errors.New("engine is not a posv engine")
}
validators := posv.ExtractValidatorsFromCheckpointHeader(header)
attestors, err := s.eth.PosvGetAttestors(s.eth.blockchain.Config().Viction, header, validators)
return attestors, err
}

func (s *EthAPIBackend) GetPenaltiesByHashAtCheckPoint(hash common.Hash) ([]common.Address, error) {
header := s.eth.blockchain.GetHeaderByHash(hash)
if header == nil || header.Number.Uint64()%s.eth.blockchain.Config().Posv.Epoch != 0 {
return nil, errors.New("header is not a checkpoint block")
}
engine, ok := s.Engine().(*posv.Posv)
if !ok {
return nil, errors.New("engine is not a posv engine")
}
validators, err := engine.GetSignersAtHash(s.eth.blockchain, header.Hash())
if err != nil {
return nil, err
}
penalties, err := s.eth.PosvGetPenalties(engine, s.eth.blockchain.Config(), s.eth.blockchain.Config().Posv, s.eth.blockchain.Config().Viction, header, s.eth.blockchain, validators)
return penalties, err
}

func (s *EthAPIBackend) GetPenaltiesByNumberAtCheckPoint(number rpc.BlockNumber) ([]common.Address, error) {
var blockNumber uint64
switch number {
case rpc.LatestBlockNumber:
blockNumber = s.CurrentBlock().NumberU64()
case rpc.PendingBlockNumber:
return nil, errors.New("pending block number is not supported")
default:
if number < 0 {
return nil, errors.New("invalid block number")
}
blockNumber = uint64(number)
}
header := s.eth.blockchain.GetHeaderByNumber(blockNumber)
if header == nil || header.Number.Uint64()%s.eth.blockchain.Config().Posv.Epoch != 0 {
return nil, errors.New("header is not a checkpoint block")
}
engine, ok := s.Engine().(*posv.Posv)
if !ok {
return nil, errors.New("engine is not a posv engine")
}
validators, err := engine.GetSignersAtHash(s.eth.blockchain, header.Hash())
if err != nil {
return nil, err
}
penalties, err := s.eth.PosvGetPenalties(engine, s.eth.blockchain.Config(), s.eth.blockchain.Config().Posv, s.eth.blockchain.Config().Viction, header, s.eth.blockchain, validators)
return penalties, err
}
46 changes: 46 additions & 0 deletions internal/ethapi/api_viction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package ethapi

import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/posv"
"github.com/ethereum/go-ethereum/rpc"
)

// PublicVictionBlockChainAPI exposes Viction/PoSV-specific read-only blockchain helpers.
type PublicVictionBlockChainAPI struct {
b BackendViction
}

func NewPublicVictionBlockChainAPI(b BackendViction) *PublicVictionBlockChainAPI {
return &PublicVictionBlockChainAPI{b}
}

// GetAttestorsPairsByHash returns attestors pairs for a checkpoint block hash.
func (s *PublicVictionBlockChainAPI) GetAttestorsPairsByHash(hash common.Hash) (map[common.Address]common.Address, error) {
return s.b.GetAttestorsPairsByHash(hash)
}

// GetAttestorsPairsByNumber returns attestors pairs for a checkpoint block number.
func (s *PublicVictionBlockChainAPI) GetAttestorsPairsByNumber(number rpc.BlockNumber) (map[common.Address]common.Address, error) {
return s.b.GetAttestorsPairsByNumber(number)
}

func (s *PublicVictionBlockChainAPI) GetRewardByHash(hash common.Hash) (*posv.EpochReward, error) {
return s.b.GetRewardByHash(hash)
}

func (s *PublicVictionBlockChainAPI) GetAttestorsByHashAtCheckPoint(hash common.Hash) ([]int64, error) {
return s.b.GetAttestorsByHashAtCheckPoint(hash)
}

func (s *PublicVictionBlockChainAPI) GetAttestorsByNumberAtCheckPoint(number rpc.BlockNumber) ([]int64, error) {
return s.b.GetAttestorsByNumberAtCheckPoint(number)
}

func (s *PublicVictionBlockChainAPI) GetPenaltiesByHashAtCheckPoint(hash common.Hash) ([]common.Address, error) {
return s.b.GetPenaltiesByHashAtCheckPoint(hash)
}

func (s *PublicVictionBlockChainAPI) GetPenaltiesByNumberAtCheckPoint(number rpc.BlockNumber) ([]common.Address, error) {
return s.b.GetPenaltiesByNumberAtCheckPoint(number)
}
20 changes: 19 additions & 1 deletion internal/ethapi/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/posv"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/state"
Expand Down Expand Up @@ -92,7 +93,7 @@ type Backend interface {

func GetAPIs(apiBackend Backend) []rpc.API {
nonceLock := new(AddrLocker)
return []rpc.API{
apis := []rpc.API{
{
Namespace: "eth",
Version: "1.0",
Expand Down Expand Up @@ -134,4 +135,21 @@ func GetAPIs(apiBackend Backend) []rpc.API {
Public: false,
},
}
// Viction RPC: only when the backend implements BackendViction (e.g. *EthAPIBackend).
// Light clients use Backend only — no BackendViction — so this block is skipped.
bv, hasViction := apiBackend.(BackendViction)
if hasViction {
if _, isPosv := bv.Engine().(*posv.Posv); isPosv {
cfg := bv.ChainConfig()
if cfg != nil && cfg.Posv != nil {
apis = append(apis, rpc.API{
Namespace: "eth",
Version: "1.0",
Service: NewPublicVictionBlockChainAPI(bv),
Public: true,
})
}
}
}
return apis
}
22 changes: 22 additions & 0 deletions internal/ethapi/backend_viction.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package ethapi

import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/posv"
"github.com/ethereum/go-ethereum/rpc"
)

// BackendViction extends Backend with Viction/PoSV helpers for eth RPC.
// Full-node *eth.EthAPIBackend implements both Backend and BackendViction.
// When the engine is *posv.Posv and ChainConfig.Posv is set, GetAPIs registers
// PublicVictionBlockChainAPI on the "eth" namespace.
type BackendViction interface {
Backend
GetRewardByHash(hash common.Hash) (*posv.EpochReward, error)
GetAttestorsPairsByHash(hash common.Hash) (map[common.Address]common.Address, error)
GetAttestorsPairsByNumber(number rpc.BlockNumber) (map[common.Address]common.Address, error)
GetAttestorsByHashAtCheckPoint(hash common.Hash) ([]int64, error)
GetAttestorsByNumberAtCheckPoint(number rpc.BlockNumber) ([]int64, error)
GetPenaltiesByHashAtCheckPoint(hash common.Hash) ([]common.Address, error)
GetPenaltiesByNumberAtCheckPoint(number rpc.BlockNumber) ([]common.Address, error)
}
Loading