mirror of
https://github.com/luxfi/precompile.git
synced 2026-09-24 00:26:21 +00:00
P0 consensus-critical:
- FHE: deterministic keygen from SHA-256("LUX_FHE_KEYGEN_v1"), StateDB
ciphertext storage (replaces ephemeral in-memory ctStore), remove
crypto/rand fallback
- time.Now() eliminated from 20 state-modifying paths across bridge (12),
dex (7), attestation (5) — all now use blockTimestamp parameter
- WebSocket: 1024-client semaphore, 64KB read limit, 60s deadline, pong
handler, origin check on chain/dag/evm indexer subscribers
P1 correctness:
- I-Chain indexer: identity.Health → identity.getLatestBlock
- Graph pagination: min(limit, 1000) cap across 25 resolver files
- Error sentinels: 31 packages unified to contract.ErrInvalidInput
P2 standardization:
- 14 packages migrated from manual gas checks to contract.DeductGas()
- Gas naming: {Name}Gas → Gas{Name} in secp256r1, ed25519, math, quasar
- Registry address format comment clarified (PCII vs legacy ranges)
37/37 precompile tests pass.
67 lines
2.0 KiB
Go
67 lines
2.0 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package contract
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/luxfi/crypto"
|
|
"github.com/luxfi/geth/accounts/abi"
|
|
)
|
|
|
|
// Shared error sentinels for all precompiles.
|
|
var (
|
|
ErrOutOfGas = errors.New("out of gas")
|
|
ErrInvalidInput = errors.New("invalid input")
|
|
ErrInvalidOp = errors.New("invalid operation")
|
|
)
|
|
|
|
// Gas costs for stateful precompiles
|
|
const (
|
|
WriteGasCostPerSlot = 20_000
|
|
ReadGasCostPerSlot = 5_000
|
|
|
|
// Per LOG operation.
|
|
LogGas uint64 = 375 // from params/protocol_params.go
|
|
// Gas cost of single topic of the LOG. Should be multiplied by the number of topics.
|
|
LogTopicGas uint64 = 375 // from params/protocol_params.go
|
|
// Per byte cost in a LOG operation's data. Should be multiplied by the byte size of the data.
|
|
LogDataGas uint64 = 8 // from params/protocol_params.go
|
|
)
|
|
|
|
var functionSignatureRegex = regexp.MustCompile(`\w+\((\w*|(\w+,)+\w+)\)`)
|
|
|
|
// CalculateFunctionSelector returns the 4 byte function selector that results from [functionSignature]
|
|
// Ex. the function setBalance(addr address, balance uint256) should be passed in as the string:
|
|
// "setBalance(address,uint256)"
|
|
func CalculateFunctionSelector(functionSignature string) []byte {
|
|
if !functionSignatureRegex.MatchString(functionSignature) {
|
|
panic(fmt.Errorf("invalid function signature: %q", functionSignature))
|
|
}
|
|
hash := crypto.Keccak256([]byte(functionSignature))
|
|
return hash[:4]
|
|
}
|
|
|
|
// DeductGas checks if [suppliedGas] is sufficient against [requiredGas] and deducts [requiredGas] from [suppliedGas].
|
|
func DeductGas(suppliedGas uint64, requiredGas uint64) (uint64, error) {
|
|
if suppliedGas < requiredGas {
|
|
return 0, ErrOutOfGas
|
|
}
|
|
return suppliedGas - requiredGas, nil
|
|
}
|
|
|
|
// ParseABI parses the given ABI string and returns the parsed ABI.
|
|
// If the ABI is invalid, it panics.
|
|
func ParseABI(rawABI string) abi.ABI {
|
|
parsed, err := abi.JSON(strings.NewReader(rawABI))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return parsed
|
|
}
|