mirror of
https://github.com/luxfi/precompile.git
synced 2026-09-24 00:26:21 +00:00
158 lines
5.0 KiB
Go
158 lines
5.0 KiB
Go
// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package modelregistry
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/binary"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/geth/common"
|
|
"github.com/luxfi/precompile/contract"
|
|
)
|
|
|
|
// State key derivation (the precompile owns its storage at ContractAddress). Internal
|
|
// storage keys (not consensus-visible ABI), so any deterministic hash works; stdlib
|
|
// sha256 avoids an external dep.
|
|
func stateKey(prefix string, data []byte) common.Hash {
|
|
h := sha256.New()
|
|
h.Write([]byte(prefix))
|
|
h.Write(data)
|
|
return common.BytesToHash(h.Sum(nil))
|
|
}
|
|
|
|
func adminKey(a common.Address) common.Hash { return stateKey("adm", a.Bytes()) }
|
|
func weightKey(name common.Hash) common.Hash { return stateKey("mw", name.Bytes()) }
|
|
func verKey(name common.Hash) common.Hash { return stateKey("mv", name.Bytes()) }
|
|
|
|
var enabledHash = common.Hash{31: 1}
|
|
|
|
func setAdminState(state contract.StateDB, a common.Address, enabled bool) {
|
|
if enabled {
|
|
state.SetState(ContractAddress, adminKey(a), enabledHash)
|
|
} else {
|
|
state.SetState(ContractAddress, adminKey(a), common.Hash{})
|
|
}
|
|
}
|
|
|
|
// IsAdmin reports whether addr may adopt models / manage admins.
|
|
func IsAdmin(state contract.StateDB, a common.Address) bool {
|
|
return state.GetState(ContractAddress, adminKey(a)) != (common.Hash{})
|
|
}
|
|
|
|
// GetApproved returns the currently-adopted (version, weight-commitment) for a model
|
|
// name. This is what the inference precompile / off-chain provisioners read to know
|
|
// which weights are the chain's canonical brain. weight == zero means none adopted yet.
|
|
func GetApproved(state contract.StateDB, name common.Hash) (version uint64, weight common.Hash) {
|
|
v := state.GetState(ContractAddress, verKey(name))
|
|
weight = state.GetState(ContractAddress, weightKey(name))
|
|
version = binary.BigEndian.Uint64(v[24:32])
|
|
return version, weight
|
|
}
|
|
|
|
// ModelRegistryContract — the governance-adopted, versioned model commitment.
|
|
type ModelRegistryContract struct{}
|
|
|
|
func (c *ModelRegistryContract) RequiredGas(input []byte) uint64 {
|
|
if len(input) < 4 {
|
|
return GasGetApproved
|
|
}
|
|
switch binary.BigEndian.Uint32(input[:4]) {
|
|
case SelectorAdopt:
|
|
return GasAdopt
|
|
case SelectorGetApproved:
|
|
return GasGetApproved
|
|
case SelectorIsAdmin:
|
|
return GasIsAdmin
|
|
case SelectorSetAdmin:
|
|
return GasSetAdmin
|
|
default:
|
|
return GasGetApproved
|
|
}
|
|
}
|
|
|
|
func boolWord(b bool) []byte {
|
|
out := make([]byte, 32)
|
|
if b {
|
|
out[31] = 1
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (c *ModelRegistryContract) Run(
|
|
accessibleState contract.AccessibleState,
|
|
caller common.Address,
|
|
_ common.Address,
|
|
input []byte,
|
|
suppliedGas uint64,
|
|
readOnly bool,
|
|
) (ret []byte, remainingGas uint64, err error) {
|
|
gas := c.RequiredGas(input)
|
|
if suppliedGas < gas {
|
|
return nil, 0, fmt.Errorf("out of gas: need %d have %d", gas, suppliedGas)
|
|
}
|
|
remainingGas = suppliedGas - gas
|
|
if len(input) < 4 {
|
|
return nil, remainingGas, fmt.Errorf("input too short")
|
|
}
|
|
selector := binary.BigEndian.Uint32(input[:4])
|
|
data := input[4:]
|
|
state := accessibleState.GetStateDB()
|
|
|
|
switch selector {
|
|
case SelectorAdopt: // adopt(bytes32 name, uint256 version, bytes32 weightHash)
|
|
if readOnly {
|
|
return nil, remainingGas, fmt.Errorf("cannot adopt in read-only mode")
|
|
}
|
|
if !IsAdmin(state, caller) {
|
|
return nil, remainingGas, fmt.Errorf("caller %s is not an admin", caller)
|
|
}
|
|
if len(data) < 96 {
|
|
return nil, remainingGas, fmt.Errorf("adopt: input too short")
|
|
}
|
|
name := common.BytesToHash(data[0:32])
|
|
version := common.BytesToHash(data[32:64])
|
|
weight := common.BytesToHash(data[64:96])
|
|
state.SetState(ContractAddress, verKey(name), version)
|
|
state.SetState(ContractAddress, weightKey(name), weight)
|
|
return boolWord(true), remainingGas, nil
|
|
|
|
case SelectorGetApproved: // getApproved(bytes32 name) -> (uint256 version, bytes32 weightHash)
|
|
if len(data) < 32 {
|
|
return nil, remainingGas, fmt.Errorf("getApproved: input too short")
|
|
}
|
|
name := common.BytesToHash(data[0:32])
|
|
ver := state.GetState(ContractAddress, verKey(name))
|
|
weight := state.GetState(ContractAddress, weightKey(name))
|
|
out := make([]byte, 64)
|
|
copy(out[0:32], ver[:])
|
|
copy(out[32:64], weight[:])
|
|
return out, remainingGas, nil
|
|
|
|
case SelectorIsAdmin: // isAdmin(address) -> bool
|
|
if len(data) < 32 {
|
|
return nil, remainingGas, fmt.Errorf("isAdmin: input too short")
|
|
}
|
|
return boolWord(IsAdmin(state, common.BytesToAddress(data[12:32]))), remainingGas, nil
|
|
|
|
case SelectorSetAdmin: // setAdmin(address, bool enabled) -> bool
|
|
if readOnly {
|
|
return nil, remainingGas, fmt.Errorf("cannot setAdmin in read-only mode")
|
|
}
|
|
if !IsAdmin(state, caller) {
|
|
return nil, remainingGas, fmt.Errorf("caller %s is not an admin", caller)
|
|
}
|
|
if len(data) < 64 {
|
|
return nil, remainingGas, fmt.Errorf("setAdmin: input too short")
|
|
}
|
|
a := common.BytesToAddress(data[12:32])
|
|
enabled := common.BytesToHash(data[32:64]) != (common.Hash{})
|
|
setAdminState(state, a, enabled)
|
|
return boolWord(true), remainingGas, nil
|
|
|
|
default:
|
|
return nil, remainingGas, fmt.Errorf("unknown selector %#x", selector)
|
|
}
|
|
}
|