mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
Updates dependencies: - github.com/luxfi/vm v1.0.22 → v1.0.23 (adds ZAP transport Serve) - github.com/luxfi/log v1.3.0 → v1.4.1 (fixes module path declaration) - github.com/luxfi/consensus v1.22.53 → v1.22.56 - github.com/luxfi/crypto v1.17.39 → v1.17.40 - github.com/luxfi/database v1.17.38 → v1.17.39 - github.com/luxfi/geth v1.16.69 → v1.16.73 - github.com/luxfi/p2p v1.18.7 → v1.18.8 - github.com/luxfi/warp v1.18.4 → v1.18.5 The vm package now provides a ZAP-based Serve function by default, eliminating the need for the grpc build tag for VM plugins. Also includes various improvements to validators, warp service, and precompile interfaces.
237 lines
7.7 KiB
Go
237 lines
7.7 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package warp
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/crypto/bls"
|
|
"github.com/luxfi/geth/common/hexutil"
|
|
"github.com/luxfi/ids"
|
|
log "github.com/luxfi/log"
|
|
"github.com/luxfi/runtime"
|
|
"github.com/luxfi/validators"
|
|
"github.com/luxfi/warp"
|
|
"github.com/luxfi/warp/payload"
|
|
|
|
warpvalidators "github.com/luxfi/evm/warp/validators"
|
|
)
|
|
|
|
var errNoValidators = errors.New("cannot aggregate signatures from network with no validators")
|
|
|
|
// API introduces chain specific functionality to the evm
|
|
type API struct {
|
|
runtimeCtx runtime.VMContext
|
|
backend Backend
|
|
signatureAggregator *warp.SignatureAggregator
|
|
requirePrimaryNetworkSigners func() bool
|
|
}
|
|
|
|
func NewAPI(runtimeCtx runtime.VMContext, backend Backend, signatureAggregator *warp.SignatureAggregator, requirePrimaryNetworkSigners func() bool) *API {
|
|
return &API{
|
|
backend: backend,
|
|
runtimeCtx: runtimeCtx,
|
|
signatureAggregator: signatureAggregator,
|
|
requirePrimaryNetworkSigners: requirePrimaryNetworkSigners,
|
|
}
|
|
}
|
|
|
|
// GetMessage returns the Warp message associated with a messageID.
|
|
func (a *API) GetMessage(ctx context.Context, messageID ids.ID) (hexutil.Bytes, error) {
|
|
message, err := a.backend.GetMessage(messageID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get message %s with error %w", messageID, err)
|
|
}
|
|
return hexutil.Bytes(message.Bytes()), nil
|
|
}
|
|
|
|
// GetMessageSignature returns the BLS signature associated with a messageID.
|
|
func (a *API) GetMessageSignature(ctx context.Context, messageID ids.ID) (hexutil.Bytes, error) {
|
|
unsignedMessage, err := a.backend.GetMessage(messageID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get message %s with error %w", messageID, err)
|
|
}
|
|
signature, err := a.backend.GetMessageSignature(ctx, unsignedMessage)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get signature for message %s with error %w", messageID, err)
|
|
}
|
|
return signature[:], nil
|
|
}
|
|
|
|
// GetBlockSignature returns the BLS signature associated with a blockID.
|
|
func (a *API) GetBlockSignature(ctx context.Context, blockID ids.ID) (hexutil.Bytes, error) {
|
|
signature, err := a.backend.GetBlockSignature(ctx, blockID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get signature for block %s with error %w", blockID, err)
|
|
}
|
|
return signature[:], nil
|
|
}
|
|
|
|
// GetMessageAggregateSignature fetches the aggregate signature for the requested [messageID]
|
|
func (a *API) GetMessageAggregateSignature(ctx context.Context, messageID ids.ID, quorumNum uint64, chainIDStr string) (signedMessageBytes hexutil.Bytes, err error) {
|
|
unsignedMessage, err := a.backend.GetMessage(messageID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return a.aggregateSignatures(ctx, unsignedMessage, quorumNum, chainIDStr)
|
|
}
|
|
|
|
// GetBlockAggregateSignature fetches the aggregate signature for the requested [blockID]
|
|
func (a *API) GetBlockAggregateSignature(ctx context.Context, blockID ids.ID, quorumNum uint64, chainIDStr string) (signedMessageBytes hexutil.Bytes, err error) {
|
|
blockHashPayload, err := payload.NewHash(blockID[:])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
chainID := a.runtimeCtx.GetChainID()
|
|
unsignedMessage, err := warp.NewUnsignedMessage(a.runtimeCtx.GetNetworkID(), chainID, blockHashPayload.Bytes())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return a.aggregateSignatures(ctx, unsignedMessage, quorumNum, chainIDStr)
|
|
}
|
|
|
|
func (a *API) aggregateSignatures(ctx context.Context, unsignedMessage *warp.UnsignedMessage, quorumNum uint64, chainIDStr string) (hexutil.Bytes, error) {
|
|
chainID := a.runtimeCtx.GetChainID()
|
|
if len(chainIDStr) > 0 {
|
|
cid, err := ids.FromString(chainIDStr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse chainID: %q", chainIDStr)
|
|
}
|
|
chainID = cid
|
|
}
|
|
|
|
// Get validator state from runtime context
|
|
validatorState := a.runtimeCtx.GetValidatorState()
|
|
if validatorState == nil {
|
|
return nil, errors.New("validator state not available")
|
|
}
|
|
|
|
// Get current P-chain height
|
|
pChainHeight, err := validatorState.GetCurrentHeight(ctx)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get current height: %w", err)
|
|
}
|
|
|
|
// Create validator state wrapper for warp messaging
|
|
// This handles the special case for Primary Network messages
|
|
sourceChainID := unsignedMessage.SourceChainID
|
|
wrappedState := warpvalidators.NewState(
|
|
validatorState,
|
|
a.runtimeCtx.GetChainID(),
|
|
sourceChainID,
|
|
a.requirePrimaryNetworkSigners(),
|
|
)
|
|
|
|
// Get canonical validator set using GetWarpValidatorSet
|
|
warpSet, err := wrappedState.GetWarpValidatorSet(ctx, pChainHeight, chainID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get warp validator set: %w", err)
|
|
}
|
|
|
|
if warpSet == nil || len(warpSet.Validators) == 0 {
|
|
return nil, fmt.Errorf("%w (ChainID: %s, Height: %d)", errNoValidators, chainID, pChainHeight)
|
|
}
|
|
|
|
// Convert WarpSet to warp.Validator slice for the external SignatureAggregator
|
|
warpValidators, totalWeight, err := convertWarpSetToValidators(warpSet)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to convert validator set: %w", err)
|
|
}
|
|
|
|
if len(warpValidators) == 0 {
|
|
return nil, fmt.Errorf("%w (ChainID: %s, Height: %d, no validators with BLS keys)", errNoValidators, chainID, pChainHeight)
|
|
}
|
|
|
|
log.Debug("Fetching signatures for aggregation",
|
|
"sourceChainID", sourceChainID,
|
|
"targetChainID", chainID,
|
|
"height", pChainHeight,
|
|
"numValidators", len(warpValidators),
|
|
"totalWeight", totalWeight,
|
|
)
|
|
|
|
// Check if signature aggregator is available
|
|
if a.signatureAggregator == nil {
|
|
return nil, errors.New("signature aggregator not configured")
|
|
}
|
|
|
|
// Create initial message with empty signature for aggregation
|
|
// The SignatureAggregator will collect signatures and update the message
|
|
emptyBitSetSig := &warp.BitSetSignature{
|
|
Signers: warp.NewBitSet(),
|
|
Signature: [bls.SignatureLen]byte{},
|
|
}
|
|
initialMessage, err := warp.NewMessage(unsignedMessage, emptyBitSetSig)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create initial message: %w", err)
|
|
}
|
|
|
|
// Aggregate signatures from validators
|
|
// quorumNum is the numerator (e.g., 67 for 67%), denominator is 100
|
|
const quorumDen uint64 = 100
|
|
signedMessage, _, _, err := a.signatureAggregator.AggregateSignatures(
|
|
ctx,
|
|
initialMessage,
|
|
nil, // justification - not needed for standard warp messages
|
|
warpValidators,
|
|
quorumNum,
|
|
quorumDen,
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to aggregate signatures: %w", err)
|
|
}
|
|
|
|
return signedMessage.Bytes(), nil
|
|
}
|
|
|
|
// convertWarpSetToValidators converts a validators.WarpSet to a slice of warp.Validator
|
|
// for use with the external SignatureAggregator
|
|
func convertWarpSetToValidators(warpSet *validators.WarpSet) ([]*warp.Validator, uint64, error) {
|
|
if warpSet == nil {
|
|
return nil, 0, errors.New("nil warp set")
|
|
}
|
|
|
|
warpValidators := make([]*warp.Validator, 0, len(warpSet.Validators))
|
|
var totalWeight uint64
|
|
|
|
for nodeID, warpValidator := range warpSet.Validators {
|
|
if warpValidator == nil {
|
|
continue
|
|
}
|
|
|
|
// Skip validators without BLS public keys (required for warp signing)
|
|
if len(warpValidator.PublicKey) == 0 {
|
|
log.Debug("Skipping validator without BLS public key",
|
|
"nodeID", nodeID,
|
|
)
|
|
continue
|
|
}
|
|
|
|
// Parse BLS public key from bytes
|
|
pubKey, err := bls.PublicKeyFromCompressedBytes(warpValidator.PublicKey)
|
|
if err != nil {
|
|
log.Debug("Skipping validator with invalid BLS public key",
|
|
"nodeID", nodeID,
|
|
"error", err,
|
|
)
|
|
continue
|
|
}
|
|
|
|
// Create warp.Validator for the external SignatureAggregator
|
|
validator := warp.NewValidator(
|
|
pubKey,
|
|
warpValidator.PublicKey,
|
|
warpValidator.Weight,
|
|
nodeID,
|
|
)
|
|
warpValidators = append(warpValidators, validator)
|
|
totalWeight += warpValidator.Weight
|
|
}
|
|
|
|
return warpValidators, totalWeight, nil
|
|
}
|