mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
eth,warp: gate EXPORT surfaces on the ⅔-stake Quasar tier, not the Nova accept tip (v1.36)
The two-tier consensus (v1.36) advances VM.Accept at a BARE MAJORITY (Nova), which is reorgable and can fork under f=1 equivocation. The Ethereum `finalized`/`safe` tags and warp cross-chain exports were still reading the accept tip — the "semantic collapse" the split exists to prevent. Re-point every EXPORT surface onto the export-final (Quasar, ⅔-by-stake) frontier consensus already exposes. #1 CRITICAL — eth `finalized`/`safe` tags: - eth.Ethereum gains a DURABLE, monotone lastQuasarHeight (SetLastQuasarHeight/LastQuasarHeight), pushed by consensus strictly AFTER accept. The plugin VM's SetLastQuasarFinalized persists it to acceptedBlockDB and reloads it on boot (readLastQuasarHeight), so the export surface never regresses on restart. - api_backend HeaderByNumber/BlockByNumber resolve Finalized(-3)/Safe(-4) to GetBlockByNumber( LastQuasarHeight) BEFORE the IsAccepted() catch-all — NEVER a block above the Quasar height. `latest`/`pending` stay on the accept tip (correct — not finality tags). - Test: TestFinalizedSafeResolveToQuasarNeverAboveIt proves finalized == the Quasar height, monotone, and never above the accepted tip. #2 HIGH — warp cross-chain export double-spend: - warp.verifyBlockMessage now requires the block be EXPORT-final (height ≤ BlockClient. LastQuasarHeight), so a validator signs a block hash only at Quasar finality, never on a reorgable Nova accept (two conflicting Nova forks could otherwise each aggregate a valid export). - WarpQuorumNumeratorMinimum floored 33 → 67 (⅔): any warp message needs ≥⅔ stake to verify, so at most one of two conflicting exports can validate (two ⅔ sets intersect on >⅓ honest stake) — restoring the ⅔-accept safety the pre-split accept tier gave for free. The consensus engine pushes the frontier via NetworkConfig.QuasarObserver; the node bridges it into the VM (separate node commit). Nova-only chains (no export surface) are unaffected. Co-authored-by: Hanzo Dev <[email protected]>
This commit is contained in:
@@ -139,6 +139,10 @@ const (
|
||||
var (
|
||||
// Set last accepted key to be longer than the keys used to store accepted block IDs.
|
||||
lastAcceptedKey = []byte("last_accepted_key")
|
||||
// quasarHeightKey stores the highest EXPORT-FINAL (Quasar, ⅔-by-stake) block number — the
|
||||
// block the eth `finalized`/`safe` tags resolve to. Persisted so the export surface never
|
||||
// regresses on restart (the in-memory consensus frontier resets to 0 until a cert re-forms).
|
||||
quasarHeightKey = []byte("quasar_export_height_key")
|
||||
acceptedPrefix = []byte("chain_accepted")
|
||||
metadataPrefix = []byte("metadata")
|
||||
warpPrefix = []byte("warp")
|
||||
@@ -1050,6 +1054,11 @@ func (vm *VM) initializeChain(lastAcceptedHash common.Hash, ethConfig ethconfig.
|
||||
vm.txPool = vm.eth.TxPool()
|
||||
vm.blockChain = vm.eth.BlockChain()
|
||||
debugLog("initializeChain: got txPool and blockChain")
|
||||
// Restore the durable EXPORT-FINAL (Quasar) height so the `finalized`/`safe` tags are correct
|
||||
// from the first RPC — before consensus re-forms a ⅔-stake cert this session. Advance-only.
|
||||
if h := vm.readLastQuasarHeight(); h > 0 {
|
||||
vm.eth.SetLastQuasarHeight(h)
|
||||
}
|
||||
// Upgrade the consensus context on the live chain to the FULL chain Runtime, which adds
|
||||
// the cross-chain atomic SharedMemory capability (the DEX 0x9999 C<->D shared-memory seam)
|
||||
// on top of the identity already bound at construction. Also covers the warp message
|
||||
@@ -2054,6 +2063,47 @@ func (vm *VM) readLastAccepted() (common.Hash, uint64, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// SetLastQuasarFinalized records that the block at `height` has reached EXPORT finality (Quasar,
|
||||
// ⅔-by-stake). It is the sink the consensus export-frontier observer pushes into — strictly AFTER
|
||||
// the block's local (Nova majority) Accept. It advances the in-memory export height the eth
|
||||
// `finalized`/`safe` tags read (eth.SetLastQuasarHeight is monotone) AND persists it so the export
|
||||
// surface survives a restart without regressing (the in-memory consensus frontier resets to 0
|
||||
// until a cert re-forms). No-op before the eth backend exists.
|
||||
func (vm *VM) SetLastQuasarFinalized(height uint64) {
|
||||
if vm.eth == nil {
|
||||
return
|
||||
}
|
||||
if height <= vm.eth.LastQuasarHeight() {
|
||||
return // monotone: the export frontier only advances
|
||||
}
|
||||
vm.eth.SetLastQuasarHeight(height)
|
||||
var buf [8]byte
|
||||
binary.BigEndian.PutUint64(buf[:], height)
|
||||
if err := vm.acceptedBlockDB.Put(quasarHeightKey, buf[:]); err != nil {
|
||||
log.Warn("failed to persist EXPORT-FINAL (quasar) height", "height", height, "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// LastQuasarHeight returns the highest EXPORT-FINAL (Quasar) block number the eth `finalized`/
|
||||
// `safe` tags resolve to (0 before the first export). The node reads it on boot to re-seed the
|
||||
// consensus export frontier so GetQuasarTip / QuasarHeight do not regress on restart.
|
||||
func (vm *VM) LastQuasarHeight() uint64 {
|
||||
if vm.eth == nil {
|
||||
return 0
|
||||
}
|
||||
return vm.eth.LastQuasarHeight()
|
||||
}
|
||||
|
||||
// readLastQuasarHeight loads the durable EXPORT-FINAL (Quasar) height from acceptedBlockDB on
|
||||
// boot. 0 (→ genesis) when never exported or missing.
|
||||
func (vm *VM) readLastQuasarHeight() uint64 {
|
||||
b, err := vm.acceptedBlockDB.Get(quasarHeightKey)
|
||||
if err != nil || len(b) != 8 {
|
||||
return 0
|
||||
}
|
||||
return binary.BigEndian.Uint64(b)
|
||||
}
|
||||
|
||||
// attachEthService registers the backend RPC services provided by Ethereum
|
||||
// to the provided handler under their assigned namespaces.
|
||||
func attachEthService(handler *rpc.Server, apis []rpc.API, names []string) error {
|
||||
|
||||
@@ -33,3 +33,10 @@ func (w *warpBlockClient) GetAcceptedBlock(ctx context.Context, blkID ids.ID) (n
|
||||
|
||||
return w.vm.newBlock(ethBlock), nil
|
||||
}
|
||||
|
||||
// LastQuasarHeight returns the VM's highest EXPORT-FINAL (Quasar, ⅔-by-stake) block number — the
|
||||
// export-tier gate for warp block signatures (a cross-chain export must sit at export finality,
|
||||
// not the reorgable local Accept tip).
|
||||
func (w *warpBlockClient) LastQuasarHeight() uint64 {
|
||||
return w.vm.LastQuasarHeight()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user