mirror of
https://github.com/luxfi/precompile.git
synced 2026-09-24 00:26:21 +00:00
Public permissionless launch policy: enable basically every precompile for builder convenience, ESPECIALLY wallet-curve VERIFY so users sign natively on Lux from other chains (ed25519=Solana, sr25519=Polkadot, secp256r1=WebAuthn, secp256k1/ecrecover=Ethereum). Disable ONLY actual security risks. Lux's own consensus and identity stay PQ (quasar/p3q) — enforced in the consensus layer, never by refusing an EVM verifier a dapp asked for. Two layers, decomplected: - builder EVM precompile surface : enable-all-verify (this change) - chain consensus / finality : PQ-strict (consensus module, untouched) Removed the RefuseUnderStrictPQ gate from 17 verify-only / key-safe custom precompiles: ed25519, sr25519, secp256r1, bls12381 (EIP-2537, x7 ops), kzg4844 (EIP-4844), blake3, poseidon, pedersen, babyjubjub, pasta, ring, vrf, hpke, curve25519, x25519, cggmp21, frost, and the classical SNARK verifiers in zk (Groth16/PLONK/Halo2/KZG/IPA/range/batch/commitment). zk fflonk (0x03) stays DISABLED — but on its OWN forge-bug mechanism (ErrFflonkDisabled, returned at dispatch), NOT strict-PQ: verifyFflonk has a nil-vk soundness hole that forges any statement. Security disable, fully PQ-independent. The RefuseUnderStrictPQ helper + ErrClassicalForbiddenInPQ + StrictPQReporter had zero remaining code callers (evm uses a local structural interface) — deleted contract/strict_pq.go and its test. Rewrote zk's gate test to assert the new policy (classical ops enabled, fflonk disabled). Removed the now- orphaned isPedersenCommitment; fixed stale comments referencing deleted symbols. Build: full module green. Tests: contract + zk + all 17 edited packages pass. NOTE: the STANDARD eth precompiles (ecrecover, p256Verify, sha256, ripemd160, blake2f, bls12381, kzg) are still refused by LuxStrictPQ() in the evm plugin — a follow-up commit flips that to Permissive so ecrecover (every Ethereum dapp) works at launch.
120 lines
4.4 KiB
Go
120 lines
4.4 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package contract
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/luxfi/precompile/precompileconfig"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// feeReportingChainConfig is a ChainConfig that also implements
|
|
// FeeConfigReporter.
|
|
type feeReportingChainConfig struct {
|
|
*MockChainConfig
|
|
// limit returned at any time before flipAt; postLimit returned at
|
|
// flipAt and later. Models feeConfigManagerConfig raising the
|
|
// gasLimit post-genesis.
|
|
limit uint64
|
|
postLimit uint64
|
|
flipAt uint64
|
|
}
|
|
|
|
func newFeeReportingChainConfig(limit, postLimit, flipAt uint64) *feeReportingChainConfig {
|
|
return &feeReportingChainConfig{
|
|
MockChainConfig: NewMockChainConfig(0),
|
|
limit: limit,
|
|
postLimit: postLimit,
|
|
flipAt: flipAt,
|
|
}
|
|
}
|
|
|
|
func (f *feeReportingChainConfig) EffectiveGasLimit(time uint64) uint64 {
|
|
if time >= f.flipAt {
|
|
return f.postLimit
|
|
}
|
|
return f.limit
|
|
}
|
|
|
|
// TestRequireGasLimit_NoReporter verifies that ChainConfigs that do
|
|
// not implement FeeConfigReporter are treated as permissive (the
|
|
// default for non-Lux chains that integrate Lux precompiles).
|
|
func TestRequireGasLimit_NoReporter(t *testing.T) {
|
|
cfg := NewMockChainConfig(0) // no FeeConfigReporter
|
|
bc := NewMockBlockContext(1, 1000)
|
|
require.NoError(t, RequireGasLimit(cfg, bc, 1<<30))
|
|
}
|
|
|
|
// TestRequireGasLimit_NilChainConfig verifies permissive behavior.
|
|
func TestRequireGasLimit_NilChainConfig(t *testing.T) {
|
|
bc := NewMockBlockContext(1, 1000)
|
|
require.NoError(t, RequireGasLimit(nil, bc, 1<<30))
|
|
}
|
|
|
|
// TestRequireGasLimit_ReporterAbove verifies that a reporter whose
|
|
// limit exceeds the threshold is permissive.
|
|
func TestRequireGasLimit_ReporterAbove(t *testing.T) {
|
|
cfg := newFeeReportingChainConfig(20_000_000, 20_000_000, 0)
|
|
bc := NewMockBlockContext(1, 1000)
|
|
require.NoError(t, RequireGasLimit(cfg, bc, 12_000_000))
|
|
}
|
|
|
|
// TestRequireGasLimit_ReporterAtThreshold verifies inclusive lower bound:
|
|
// a reporter at exactly the threshold passes (min is the floor, not exclusive).
|
|
func TestRequireGasLimit_ReporterAtThreshold(t *testing.T) {
|
|
cfg := newFeeReportingChainConfig(12_000_000, 12_000_000, 0)
|
|
bc := NewMockBlockContext(1, 1000)
|
|
require.NoError(t, RequireGasLimit(cfg, bc, 12_000_000))
|
|
}
|
|
|
|
// TestRequireGasLimit_ReporterBelow verifies that a reporter whose
|
|
// limit is below the threshold refuses with ErrFHEUnsafeGasLimit.
|
|
func TestRequireGasLimit_ReporterBelow(t *testing.T) {
|
|
cfg := newFeeReportingChainConfig(8_000_000, 8_000_000, 0)
|
|
bc := NewMockBlockContext(1, 1000)
|
|
err := RequireGasLimit(cfg, bc, 12_000_000)
|
|
require.ErrorIs(t, err, ErrFHEUnsafeGasLimit)
|
|
}
|
|
|
|
// TestRequireGasLimit_ReporterAbstains verifies that EffectiveGasLimit
|
|
// returning 0 (reporter has no opinion) is treated as permissive.
|
|
func TestRequireGasLimit_ReporterAbstains(t *testing.T) {
|
|
cfg := newFeeReportingChainConfig(0, 0, 0)
|
|
bc := NewMockBlockContext(1, 1000)
|
|
require.NoError(t, RequireGasLimit(cfg, bc, 12_000_000))
|
|
}
|
|
|
|
// TestRequireGasLimit_TimeAware verifies that the reporter is queried
|
|
// at the activation block timestamp — models feeConfigManagerConfig
|
|
// raising the gasLimit post-genesis.
|
|
func TestRequireGasLimit_TimeAware(t *testing.T) {
|
|
// Mainnet shape: genesis 12M, fee-manager raises to 20M at t=900000000.
|
|
cfg := newFeeReportingChainConfig(12_000_000, 20_000_000, 900_000_000)
|
|
|
|
// Before the flip: refuses because 12M < 15M threshold.
|
|
bcEarly := NewMockBlockContext(1, 500_000_000)
|
|
require.ErrorIs(t, RequireGasLimit(cfg, bcEarly, 15_000_000), ErrFHEUnsafeGasLimit)
|
|
|
|
// After the flip: passes because 20M >= 15M threshold.
|
|
bcLate := NewMockBlockContext(1, 1_000_000_000)
|
|
require.NoError(t, RequireGasLimit(cfg, bcLate, 15_000_000))
|
|
}
|
|
|
|
// TestRequireGasLimit_NilBlockContext verifies that nil blockContext
|
|
// is treated as time=0 (chain genesis) and the genesis-time gasLimit
|
|
// is the one evaluated.
|
|
func TestRequireGasLimit_NilBlockContext(t *testing.T) {
|
|
cfg := newFeeReportingChainConfig(12_000_000, 20_000_000, 900_000_000)
|
|
require.ErrorIs(t, RequireGasLimit(cfg, nil, 15_000_000), ErrFHEUnsafeGasLimit)
|
|
}
|
|
|
|
// TestFeeConfigReporter_InterfaceShape is a compile-time check that
|
|
// the test reporter type satisfies both ChainConfig and
|
|
// FeeConfigReporter.
|
|
func TestFeeConfigReporter_InterfaceShape(t *testing.T) {
|
|
var _ FeeConfigReporter = (*feeReportingChainConfig)(nil)
|
|
var _ precompileconfig.ChainConfig = (*feeReportingChainConfig)(nil)
|
|
}
|