evm: FIX native-MINT bug in precompile StateDB bridge + precompile v0.5.44

CRITICAL: stateDBBridge.SubBalance type-asserts the concrete adapter else SILENTLY no-ops; the
internal contract.StateDB had AddBalance but no SubBalance and stateDBAdapter only implemented
AddBalance → a precompile debiting native value (DEX withdraw) CREDITED the caller while debiting
NOTHING = native mint (caught live: vault 100000, wallet +100000). The DEX is the first precompile
to debit native value so the path was never exercised. Added stateDBAdapter.SubBalance + regression
guard (core/precompile_statedb_subbalance_test.go); zero 'SubBalance fallback' warnings. Bump
precompile v0.5.43→v0.5.44 (PoolManager pure-ingress custody).
This commit is contained in:
2026-06-17 22:30:58 -07:00
parent c45e87b670
commit 3d9ee0fb4f
4 changed files with 78 additions and 3 deletions
+14
View File
@@ -168,6 +168,20 @@ func (s *stateDBAdapter) AddBalance(addr common.Address, amount *uint256.Int) {
s.stateDB.AddBalance(addr, amount, tracing.BalanceChangeUnspecified)
}
// SubBalance forwards to the underlying vm.StateDB with the FULL external
// signature (addr, amount, reason) -> prev. The registry's stateDBBridge type-
// asserts the internal contract.StateDB for exactly this method so that a
// precompile which moves native value (e.g. the DEX 0x9010 custody vault: a
// withdraw debits the vault before releasing to the caller) actually subtracts
// the balance instead of hitting the bridge's no-op fallback. AddBalance is the
// narrow internal pair; SubBalance is provided here so the pair is complete on
// the concrete adapter without widening the internal interface (which has many
// implementers/mocks). Without this the bridge logged "SubBalance fallback used"
// and silently MINTED native value (vault unchanged, caller credited).
func (s *stateDBAdapter) SubBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
return s.stateDB.SubBalance(addr, amount, reason)
}
func (s *stateDBAdapter) CreateAccount(addr common.Address) {
s.stateDB.CreateAccount(addr)
}
@@ -0,0 +1,61 @@
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package core
import (
"testing"
"github.com/holiman/uint256"
"github.com/luxfi/geth/common"
"github.com/luxfi/geth/core/tracing"
)
// precompile_statedb_subbalance_test.go pins the fix for a LATENT bug: the
// precompile registry's stateDBBridge.SubBalance type-asserts the internal
// contract.StateDB for the EXTERNAL SubBalance signature
//
// SubBalance(common.Address, *uint256.Int, tracing.BalanceChangeReason) uint256.Int
//
// and falls back to a NO-OP (logging "SubBalance fallback used") when the
// assertion fails. The concrete adapter the EVM hands precompiles is
// *stateDBAdapter; if it does not implement that EXACT signature, a precompile
// that debits native value — e.g. the DEX 0x9010 custody vault, whose withdraw
// debits the vault before releasing to the caller — would silently MINT (caller
// credited, vault never debited). The fix added SubBalance to *stateDBAdapter so
// the bridge's assertion succeeds and the fallback is unreachable.
// subBalancer is the EXACT interface precompile/registry/bridge.go type-asserts.
// Keep it byte-identical so this test fails if the bridge's expected signature or
// the adapter's method ever drifts.
type subBalancer interface {
SubBalance(common.Address, *uint256.Int, tracing.BalanceChangeReason) uint256.Int
}
// TestStateDBAdapter_SatisfiesSubBalancer is the regression guard: *stateDBAdapter
// MUST satisfy the subBalancer interface the registry bridge type-asserts. If this
// fails to compile or asserts false, the bridge would hit its mint fallback for
// every precompile native-value debit (the DEX withdraw vault-release).
func TestStateDBAdapter_SatisfiesSubBalancer(t *testing.T) {
// Compile-time assertion (the primary guard against signature drift).
var _ subBalancer = (*stateDBAdapter)(nil)
// Runtime assertion mirroring exactly what the bridge does:
// if sb, ok := s.internal.(subBalancer); ok { return sb.SubBalance(...) }
var adapter contractStateDBSurface = (*stateDBAdapter)(nil)
if _, ok := interface{}(adapter).(subBalancer); !ok {
t.Fatal("*stateDBAdapter does NOT satisfy subBalancer — the registry bridge would hit the mint fallback for native-value debits")
}
// A non-nil *uint256.Int sanity reference (keeps the import meaningful and the
// signature exercised in source).
_ = uint256.NewInt(0)
}
// contractStateDBSurface is the minimal surface we hold the adapter as for the
// runtime assertion — it is satisfied by *stateDBAdapter (which implements the
// full internal contract.StateDB). Held as an interface value so the type
// assertion to subBalancer is a genuine runtime check, not a compile-time tautology.
type contractStateDBSurface interface {
GetBalance(common.Address) *uint256.Int
AddBalance(common.Address, *uint256.Int)
}
+1 -1
View File
@@ -32,7 +32,7 @@ require (
github.com/luxfi/metric v1.5.8
github.com/luxfi/p2p v1.21.1
github.com/luxfi/pq v1.0.3
github.com/luxfi/precompile v0.5.43
github.com/luxfi/precompile v0.5.44
github.com/luxfi/runtime v1.1.1
github.com/luxfi/sys v0.1.0
github.com/luxfi/timer v1.0.2
+2 -2
View File
@@ -278,8 +278,8 @@ github.com/luxfi/p2p v1.21.1 h1:gmz1JMDhzHIL3dQlhwIDvR4OlFuhNVfnWUl/ipYhAIo=
github.com/luxfi/p2p v1.21.1/go.mod h1:SsNPR5fPGWWNem9plGWhSmRqyDoysJ3kPAN0zG0g3iw=
github.com/luxfi/pq v1.0.3 h1:pFlQm1+5FuKTDUh2y/23bXWkN4I2Rc5iuxJypwDFFMs=
github.com/luxfi/pq v1.0.3/go.mod h1:8bppZcRElfrVt0n3nYCZW3iX1TvhvzNbdjNdK1irgIE=
github.com/luxfi/precompile v0.5.43 h1:FaijObCK1+z1CppNIFG6i9/0C/R+IUE9VNcA5WMRx9A=
github.com/luxfi/precompile v0.5.43/go.mod h1:FYfq9CT8XRmlpjFAtblHAMcpnjByuoM+YpKq/FF9QVk=
github.com/luxfi/precompile v0.5.44 h1:r5g98nYTwHX0v7mOpico8Lksc/MInSHEaK/ST+QwKfc=
github.com/luxfi/precompile v0.5.44/go.mod h1:FYfq9CT8XRmlpjFAtblHAMcpnjByuoM+YpKq/FF9QVk=
github.com/luxfi/proto v1.3.4 h1:dNrdQ/414Pe9otIekVUmQ9QLqemaMFK43H4N3DIbuzQ=
github.com/luxfi/proto v1.3.4/go.mod h1:S80KrTzISCktptit/pWLzk6nHgagjJS86qbQL6gHutE=
github.com/luxfi/resource v0.0.1 h1:mTh+ICWSy548GTUSSyx7V/X5dV18oEwxZeQEYGJQhD4=