Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2333d3e
feat: create vote-ext-handler module
yusufozmis Mar 12, 2026
9ec486d
feat: add vote extension body as proto type
yusufozmis Mar 12, 2026
e3fbc1a
feat: allow validators to have mina private key to sign vote extensions
yusufozmis Mar 12, 2026
f36bd59
feat: add global functions for validator maps
yusufozmis Mar 12, 2026
e6e3a56
feat: change register keys in a way that will also insert validator keys
yusufozmis Mar 12, 2026
d7c5d4d
test: fix user register keys tests according to new logic
yusufozmis Mar 12, 2026
047d099
fix(keyregistry): msg.creator address derive logic
yusufozmis Mar 12, 2026
82e49b1
fix: initialize validator maps
yusufozmis Mar 12, 2026
49983ac
refactor(keyregistry): rename proto query fields for consistency
yusufozmis Mar 12, 2026
d9bb1ae
test(keyregistry): add tests for query validator maps
yusufozmis Mar 12, 2026
72580be
refactor(keyregistry): rename old maps
yusufozmis Mar 12, 2026
31fbfe4
feat: allow validators to add keypairs on genesis
yusufozmis Mar 12, 2026
c1897a7
chore(keyregistry): fix comment lines
yusufozmis Mar 12, 2026
78844f7
feat(voteexthandler): add extendvote and verifyextendvote
yusufozmis Mar 13, 2026
3c2c925
feat(voteexthandler): create voteext and voteext index messages
yusufozmis Mar 13, 2026
40b03c6
feat: implement preblocker/prepare proposal and process proposal
yusufozmis Mar 13, 2026
1b0975a
fix: add mina priv key to voteexthandler and remove unnecessary proto
yusufozmis Mar 13, 2026
a5623b6
feat: enable vote extensions
yusufozmis Mar 13, 2026
47723b0
chore: move errors to module
yusufozmis Mar 13, 2026
f2d2359
chore: cleaner vote ext functions
yusufozmis Mar 14, 2026
aabe8bc
chore: remove loggers and switch to iteratelastvalidators
yusufozmis Mar 14, 2026
721833d
fix: enable vote extensions and remove getsecondarykey helper func
yusufozmis Mar 15, 2026
f8ba750
refactor(keyregistry): users use addr instead of pubkey
yusufozmis Mar 15, 2026
210df00
fix(keyregistry): query proto error fixed
yusufozmis Mar 15, 2026
cc0aed0
fix: config.yml enable vote ext and extend_vote
yusufozmis Mar 15, 2026
ed99a9c
refactor: changed validator keypairs to ed25519
korayakpinar Mar 15, 2026
26c43f6
test: updated tests for keyregistry
korayakpinar Mar 15, 2026
170a1be
refactor: fixed the extension verification
korayakpinar Mar 15, 2026
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
198 changes: 198 additions & 0 deletions abci/extend_vote.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
package vote_ext

import (
"encoding/json"
"fmt"

"cosmossdk.io/errors"
abci "github.com/cometbft/cometbft/abci/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/node101-io/mina-signer-go/constants"
"github.com/node101-io/mina-signer-go/field"
"github.com/node101-io/mina-signer-go/poseidon"
"github.com/node101-io/pulsar-chain/x/voteexthandler/types"
voteexthandler "github.com/node101-io/pulsar-chain/x/voteexthandler/types"
)

var hardcoded = [32]byte{
0x7a, 0x13, 0x9f, 0x42, 0xd1, 0x8c, 0x5e, 0xa7,
0x2b, 0x6d, 0xf0, 0x91, 0x3c, 0x47, 0xb8, 0x0e,
0x55, 0x1a, 0xcd, 0x72, 0x98, 0x04, 0xe6, 0xaf,
0x39, 0xb2, 0x7c, 0x5d, 0x11, 0x8e, 0xf3, 0x64,
}

// ValidatorInfo represents a validator in the set
type ValidatorInfo struct {
MinaAddress string
Power int64
}

/*
func (h *VoteExtHandler) wrapValidatorInfo(ctx sdk.Context) ([]ValidatorInfo, error) {
var initialValidators []ValidatorInfo
var callbackErr error

err := h.stakingKeeper.IterateLastValidators(ctx, func(index int64, validator stakingtypes.ValidatorI) (stop bool) {
consAddr, err := validator.ConsPubKey()
if err != nil {
callbackErr = errors.Wrap(types.ErrInternal, err.Error())
return true
}

exists, err := h.keyregistryKeeper.ValidatorCosmosToMinaHas(ctx, consAddr.Bytes())
if err != nil {
callbackErr = errors.Wrap(types.ErrInternal, err.Error())
return true
}
if !exists {
callbackErr = errors.Wrap(types.ErrFailedToGetKeystore, "")
return true
}

minaPubKey, err := h.keyregistryKeeper.ValidatorGetCosmosToMina(ctx, consAddr.Bytes())
if err != nil {
callbackErr = errors.Wrap(types.ErrInternal, err.Error())
return true
}

initialValidators = append(initialValidators, ValidatorInfo{
MinaAddress: string(minaPubKey),
Power: validator.GetConsensusPower(h.stakingKeeper.PowerReduction(ctx)),
})
return false
})
if err != nil {
return nil, err
}
if callbackErr != nil {
return nil, callbackErr
}

initialValidators = h.sortValidators(initialValidators)
return initialValidators, nil
}*/

// TODO: Update this method when switching to consumer chain
func (h *VoteExtHandler) constructMinaSignatureVoteExt(extBody voteexthandler.Body, ctx sdk.Context, hash *poseidon.Poseidon) (MinaSignatureVoteExt, error) {

// Hash the vote extension body
extBodyHashInput := extBody.GetPoseidonHashInput(ctx, hash)

// Sign the vote extension body
signature, err := h.MinaPrivateKey.SecretKey.Sign(extBodyHashInput, types.DevnetNetworkID)
if err != nil {
return MinaSignatureVoteExt{}, errors.Wrap(types.ErrFailedToSign, err.Error())
}

sigBytes, err := signature.MarshalBytes()
if err != nil {
return MinaSignatureVoteExt{}, errors.Wrap(types.ErrFailedToMarshal, err.Error())
}

minaAddress, err := h.MinaPrivateKey.PublicKey.ToAddress()
if err != nil {
return MinaSignatureVoteExt{}, errors.Wrap(types.ErrFailedToConvertPubKeyToAddr, err.Error())
}

voteExt := MinaSignatureVoteExt{
MinaAddress: minaAddress,
Signature: sigBytes,
VoteExtBody: extBody,
}

return voteExt, nil
}

func (h *VoteExtHandler) constructVoteExtBody(ctx sdk.Context, req *abci.RequestExtendVote, hash poseidon.Poseidon) (voteexthandler.Body, error) {

/*validatorUpdates, err := h.stakingKeeper.GetValidatorUpdates(ctx)
if err != nil {
return voteexthandler.Body{}, err
}

initialValidators, err := h.wrapValidatorInfo(ctx)
if err != nil {
return voteexthandler.Body{}, err
}

initValSetRoot, err := h.computeValidatorSetMerkleRoot(initialValidators, &hash)
if err != nil {
return voteexthandler.Body{}, errors.Wrap(types.ErrFailedToComputeInitialValidatorSetRoot, err.Error())
}*/

prevStateRoot := h.stateRoots[req.GetHeight()-1]
initStateRoot := h.stateRoots[req.GetHeight()]

var extBody voteexthandler.Body

Check failure on line 126 in abci/extend_vote.go

View workflow job for this annotation

GitHub Actions / golangci-lint

S1021: should merge variable declaration with assignment on next line (gosimple)

Check failure on line 126 in abci/extend_vote.go

View workflow job for this annotation

GitHub Actions / golangci-lint

S1021: should merge variable declaration with assignment on next line (gosimple)
/*if len(validatorUpdates) != 0 {

// Apply validator set updates to the initial validator set and create merkle tree from the new validator set
newValidatorSet, err := h.applyValidatorUpdates(ctx, initialValidators, validatorUpdates)
if err != nil {
return voteexthandler.Body{}, errors.Wrap(types.ErrFailedToApplyValidatorUpdates, "ExtendVoteHandler"+err.Error())
}

newValSetRoot, err := h.computeValidatorSetMerkleRoot(newValidatorSet, &hash)
if err != nil {
return voteexthandler.Body{}, errors.Wrap(types.ErrFailedToComputeNewSetRoot, err.Error())
}

// Construct the vote extension body
extBody = voteexthandler.Body{
InitialValidatorSetRoot: initValSetRoot.Bytes(),
InitialBlockHeight: req.GetHeight() - 1,
InitialStateRoot: prevStateRoot,
NewValidatorSetRoot: newValSetRoot.Bytes(),
NewBlockHeight: req.GetHeight(),
NewStateRoot: initStateRoot,
}
} else {
extBody = voteexthandler.Body{
InitialValidatorSetRoot: initValSetRoot.Bytes(),
InitialBlockHeight: req.GetHeight() - 1,
InitialStateRoot: prevStateRoot,
NewValidatorSetRoot: initValSetRoot.Bytes(),
NewBlockHeight: req.GetHeight(),
NewStateRoot: initStateRoot,
}
}*/

extBody = voteexthandler.Body{
InitialValidatorSetRoot: hardcoded[:],
InitialBlockHeight: req.GetHeight() - 1,
InitialStateRoot: prevStateRoot,
NewValidatorSetRoot: hardcoded[:],
NewBlockHeight: req.GetHeight(),
NewStateRoot: initStateRoot,
}

return extBody, nil
}

func (h *VoteExtHandler) ExtendVoteHandler() sdk.ExtendVoteHandler {
return func(ctx sdk.Context, req *abci.RequestExtendVote) (*abci.ResponseExtendVote, error) {

// Initialize poseidon hash
poseidonHash := poseidon.CreatePoseidon(*field.Fp, constants.PoseidonParamsKimchiFp)

voteExtBody, err := h.constructVoteExtBody(ctx, req, *poseidonHash)
if err != nil {
return nil, err
}
voteExt, err := h.constructMinaSignatureVoteExt(voteExtBody, ctx, poseidonHash)
if err != nil {
return nil, err
}
bz, err := json.Marshal(voteExt)
if err != nil {
return nil, errors.Wrap(types.ErrFailedToMarshal, err.Error())
}

// Store vote extension in memory
h.storeVote(uint64(req.GetHeight()), voteExt.MinaAddress, bz)

ctx.Logger().Info(fmt.Sprintf("Constructed vote extension for height %d: %+v", req.GetHeight(), voteExt))

return &abci.ResponseExtendVote{VoteExtension: bz}, nil
}
}
Loading
Loading