Add Opus native contract for AI workforce integration
Implement comprehensive AI workforce management infrastructure: - Operator profiles: Registration (requires Vita), verification, supervision via RoleOpusSupervisor (ID 24) - AI Worker lifecycle: Registration, updates, suspension, decommissioning with operator ownership tracking - Task system: Assignment, progress tracking, completion, cancellation, and dispute resolution - Capability certification: Proficiency levels, certification tracking, and supervisor-managed verification - AI Tribute: Configurable percentage of AI-generated value directed to Treasury for societal benefit - Cross-contract integration: - Vita: Operator identity verification - Lex: Labor rights enforcement (RightLabor) - RoleRegistry: Supervisor role authorization - VTS: Registration fees and task payments - Treasury: Tribute collection Contract ID: -22, following Tribute (-21) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
1d96eb7a6e
commit
0e980e7342
|
|
@ -224,6 +224,10 @@ type Blockchain struct {
|
|||
lex native.ILex
|
||||
eligere native.IEligere
|
||||
scire native.IScire
|
||||
salus native.ISalus
|
||||
sese native.ISese
|
||||
tribute native.ITribute
|
||||
opus native.IOpus
|
||||
|
||||
extensible atomic.Value
|
||||
|
||||
|
|
@ -495,6 +499,22 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger, newN
|
|||
if err := validateNative(bc.scire, nativeids.Scire, nativenames.Scire, nativehashes.Scire); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bc.salus = bc.contracts.Salus()
|
||||
if err := validateNative(bc.salus, nativeids.Salus, nativenames.Salus, nativehashes.Salus); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bc.sese = bc.contracts.Sese()
|
||||
if err := validateNative(bc.sese, nativeids.Sese, nativenames.Sese, nativehashes.Sese); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bc.tribute = bc.contracts.Tribute()
|
||||
if err := validateNative(bc.tribute, nativeids.Tribute, nativenames.Tribute, nativehashes.Tribute); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bc.opus = bc.contracts.Opus()
|
||||
if err := validateNative(bc.opus, nativeids.Opus, nativenames.Opus, nativehashes.Opus); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bc.persistCond = sync.NewCond(&bc.lock)
|
||||
bc.gcBlockTimes, _ = lru.New[uint32, uint64](defaultBlockTimesCache) // Never errors for positive size
|
||||
|
|
|
|||
|
|
@ -238,6 +238,60 @@ type (
|
|||
// Address returns the contract's script hash.
|
||||
Address() util.Uint160
|
||||
}
|
||||
|
||||
// ISalus is an interface required from native Salus contract for
|
||||
// interaction with Blockchain and other native contracts.
|
||||
// Salus provides universal healthcare infrastructure.
|
||||
ISalus interface {
|
||||
interop.Contract
|
||||
// GetAccountByOwner returns a healthcare account by owner address.
|
||||
GetAccountByOwner(d *dao.Simple, owner util.Uint160) (*state.HealthcareAccount, error)
|
||||
// HasValidAuthorization checks if provider has valid authorization for patient.
|
||||
HasValidAuthorization(d *dao.Simple, patient util.Uint160, provider util.Uint160, blockHeight uint32) bool
|
||||
// Address returns the contract's script hash.
|
||||
Address() util.Uint160
|
||||
}
|
||||
|
||||
// ISese is an interface required from native Sese contract for
|
||||
// interaction with Blockchain and other native contracts.
|
||||
// Sese provides life planning infrastructure.
|
||||
ISese interface {
|
||||
interop.Contract
|
||||
// GetAccountByOwner returns a life plan account by owner address.
|
||||
GetAccountByOwner(d *dao.Simple, owner util.Uint160) (*state.LifePlanAccount, error)
|
||||
// HasActiveCareer checks if owner has an active career.
|
||||
HasActiveCareer(d *dao.Simple, owner util.Uint160) bool
|
||||
// Address returns the contract's script hash.
|
||||
Address() util.Uint160
|
||||
}
|
||||
|
||||
// ITribute is an interface required from native Tribute contract for
|
||||
// interaction with Blockchain and other native contracts.
|
||||
// Tribute provides anti-hoarding economics with velocity tracking.
|
||||
ITribute interface {
|
||||
interop.Contract
|
||||
// GetAccountByOwner returns a velocity account by owner address.
|
||||
GetAccountByOwner(d *dao.Simple, owner util.Uint160) (*state.VelocityAccount, error)
|
||||
// GetVelocity returns the current velocity score for an owner.
|
||||
GetVelocity(d *dao.Simple, owner util.Uint160) uint64
|
||||
// IsHoarding returns true if owner is hoarding resources.
|
||||
IsHoarding(d *dao.Simple, owner util.Uint160) bool
|
||||
// Address returns the contract's script hash.
|
||||
Address() util.Uint160
|
||||
}
|
||||
|
||||
// IOpus provides AI workforce integration and management.
|
||||
IOpus interface {
|
||||
interop.Contract
|
||||
// GetWorkerByID returns an AI worker by ID.
|
||||
GetWorkerByID(d *dao.Simple, workerID uint64) (*state.AIWorker, error)
|
||||
// GetOperatorByOwner returns an operator profile by owner address.
|
||||
GetOperatorByOwner(d *dao.Simple, owner util.Uint160) (*state.OperatorProfile, error)
|
||||
// IsWorkerActive returns true if the AI worker is active.
|
||||
IsWorkerActive(d *dao.Simple, workerID uint64) bool
|
||||
// Address returns the contract's script hash.
|
||||
Address() util.Uint160
|
||||
}
|
||||
)
|
||||
|
||||
// Contracts is a convenient wrapper around an arbitrary set of native contracts
|
||||
|
|
@ -401,6 +455,30 @@ func (cs *Contracts) Scire() IScire {
|
|||
return cs.ByName(nativenames.Scire).(IScire)
|
||||
}
|
||||
|
||||
// Salus returns native ISalus contract implementation. It panics if
|
||||
// there's no contract with proper name in cs.
|
||||
func (cs *Contracts) Salus() ISalus {
|
||||
return cs.ByName(nativenames.Salus).(ISalus)
|
||||
}
|
||||
|
||||
// Sese returns native ISese contract implementation. It panics if
|
||||
// there's no contract with proper name in cs.
|
||||
func (cs *Contracts) Sese() ISese {
|
||||
return cs.ByName(nativenames.Sese).(ISese)
|
||||
}
|
||||
|
||||
// Tribute returns native ITribute contract implementation. It panics if
|
||||
// there's no contract with proper name in cs.
|
||||
func (cs *Contracts) Tribute() ITribute {
|
||||
return cs.ByName(nativenames.Tribute).(ITribute)
|
||||
}
|
||||
|
||||
// Opus returns native IOpus contract implementation. It panics if
|
||||
// there's no contract with proper name in cs.
|
||||
func (cs *Contracts) Opus() IOpus {
|
||||
return cs.ByName(nativenames.Opus).(IOpus)
|
||||
}
|
||||
|
||||
// NewDefaultContracts returns a new set of default native contracts.
|
||||
func NewDefaultContracts(cfg config.ProtocolConfiguration) []interop.Contract {
|
||||
mgmt := NewManagement()
|
||||
|
|
@ -501,6 +579,37 @@ func NewDefaultContracts(cfg config.ProtocolConfiguration) []interop.Contract {
|
|||
scire.RoleRegistry = roleRegistry
|
||||
scire.Lex = lex
|
||||
|
||||
// Create Salus (Universal Healthcare) contract
|
||||
salus := newSalus()
|
||||
salus.NEO = neo
|
||||
salus.Vita = vita
|
||||
salus.RoleRegistry = roleRegistry
|
||||
salus.Lex = lex
|
||||
|
||||
// Create Sese (Life Planning) contract
|
||||
sese := newSese()
|
||||
sese.NEO = neo
|
||||
sese.Vita = vita
|
||||
sese.RoleRegistry = roleRegistry
|
||||
sese.Lex = lex
|
||||
|
||||
// Create Tribute (Anti-Hoarding Economics) contract
|
||||
tribute := newTribute()
|
||||
tribute.NEO = neo
|
||||
tribute.Vita = vita
|
||||
tribute.VTS = vts
|
||||
tribute.RoleRegistry = roleRegistry
|
||||
tribute.Lex = lex
|
||||
|
||||
// Create Opus (AI Workforce Integration) contract
|
||||
opus := newOpus()
|
||||
opus.NEO = neo
|
||||
opus.Vita = vita
|
||||
opus.VTS = vts
|
||||
opus.RoleRegistry = roleRegistry
|
||||
opus.Lex = lex
|
||||
opus.Treasury = treasury
|
||||
|
||||
return []interop.Contract{
|
||||
mgmt,
|
||||
s,
|
||||
|
|
@ -520,5 +629,9 @@ func NewDefaultContracts(cfg config.ProtocolConfiguration) []interop.Contract {
|
|||
lex,
|
||||
eligere,
|
||||
scire,
|
||||
salus,
|
||||
sese,
|
||||
tribute,
|
||||
opus,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,254 @@
|
|||
package native_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tutus-one/tutus-chain/pkg/core/native/nativenames"
|
||||
"github.com/tutus-one/tutus-chain/pkg/neotest"
|
||||
"github.com/tutus-one/tutus-chain/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
func newOpusClient(t *testing.T) *neotest.ContractInvoker {
|
||||
return newNativeClient(t, nativenames.Opus)
|
||||
}
|
||||
|
||||
// TestOpus_GetConfig tests the getConfig method.
|
||||
func TestOpus_GetConfig(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
|
||||
// Get default config
|
||||
c.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
|
||||
require.Equal(t, 1, len(stack))
|
||||
arr, ok := stack[0].Value().([]stackitem.Item)
|
||||
require.True(t, ok, "expected array result")
|
||||
require.GreaterOrEqual(t, len(arr), 7) // OpusConfig has 7 fields
|
||||
}, "getConfig")
|
||||
}
|
||||
|
||||
// TestOpus_GetTotalOperators tests the getTotalOperators method.
|
||||
func TestOpus_GetTotalOperators(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
|
||||
// Initially should be 0
|
||||
c.Invoke(t, 0, "getTotalOperators")
|
||||
}
|
||||
|
||||
// TestOpus_GetTotalWorkers tests the getTotalWorkers method.
|
||||
func TestOpus_GetTotalWorkers(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
|
||||
// Initially should be 0
|
||||
c.Invoke(t, 0, "getTotalWorkers")
|
||||
}
|
||||
|
||||
// TestOpus_GetTotalTasks tests the getTotalTasks method.
|
||||
func TestOpus_GetTotalTasks(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
|
||||
// Initially should be 0
|
||||
c.Invoke(t, 0, "getTotalTasks")
|
||||
}
|
||||
|
||||
// TestOpus_GetTotalCapabilities tests the getTotalCapabilities method.
|
||||
func TestOpus_GetTotalCapabilities(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
|
||||
// Initially should be 0
|
||||
c.Invoke(t, 0, "getTotalCapabilities")
|
||||
}
|
||||
|
||||
// TestOpus_GetOperator_NonExistent tests getting a non-existent operator.
|
||||
func TestOpus_GetOperator_NonExistent(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
e := c.Executor
|
||||
|
||||
acc := e.NewAccount(t)
|
||||
|
||||
// Non-existent operator should return null
|
||||
c.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
|
||||
require.Equal(t, 1, len(stack))
|
||||
require.Nil(t, stack[0].Value(), "expected null for non-existent operator")
|
||||
}, "getOperator", acc.ScriptHash())
|
||||
}
|
||||
|
||||
// TestOpus_GetWorker_NonExistent tests getting a non-existent worker.
|
||||
func TestOpus_GetWorker_NonExistent(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
|
||||
// Non-existent worker should return null
|
||||
c.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
|
||||
require.Equal(t, 1, len(stack))
|
||||
require.Nil(t, stack[0].Value(), "expected null for non-existent worker")
|
||||
}, "getWorker", int64(999))
|
||||
}
|
||||
|
||||
// TestOpus_GetTask_NonExistent tests getting a non-existent task.
|
||||
func TestOpus_GetTask_NonExistent(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
|
||||
// Non-existent task should return null
|
||||
c.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
|
||||
require.Equal(t, 1, len(stack))
|
||||
require.Nil(t, stack[0].Value(), "expected null for non-existent task")
|
||||
}, "getTask", int64(999))
|
||||
}
|
||||
|
||||
// TestOpus_GetCapability_NonExistent tests getting a non-existent capability.
|
||||
func TestOpus_GetCapability_NonExistent(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
|
||||
// Non-existent capability should return null
|
||||
c.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
|
||||
require.Equal(t, 1, len(stack))
|
||||
require.Nil(t, stack[0].Value(), "expected null for non-existent capability")
|
||||
}, "getCapability", int64(999))
|
||||
}
|
||||
|
||||
// Note: isWorkerActive and isOperatorVerified methods are not exposed as separate methods.
|
||||
// Worker/operator status can be checked via getWorker/getOperator.
|
||||
|
||||
// TestOpus_GetWorkerCountByOperator_NonExistent tests getting worker count for non-existent operator.
|
||||
func TestOpus_GetWorkerCountByOperator_NonExistent(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
e := c.Executor
|
||||
|
||||
acc := e.NewAccount(t)
|
||||
|
||||
// Non-existent operator should return 0
|
||||
c.Invoke(t, 0, "getWorkerCountByOperator", acc.ScriptHash())
|
||||
}
|
||||
|
||||
// TestOpus_RegisterOperator_NoVita tests that registering operator without Vita fails.
|
||||
func TestOpus_RegisterOperator_NoVita(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
e := c.Executor
|
||||
|
||||
acc := e.NewAccount(t)
|
||||
invoker := c.WithSigners(acc)
|
||||
|
||||
// Should fail - no Vita registered
|
||||
invoker.InvokeFail(t, "operator must have an active Vita", "registerOperator",
|
||||
acc.ScriptHash())
|
||||
}
|
||||
|
||||
// TestOpus_VerifyOperator_NotSupervisor tests that non-supervisor cannot verify operator.
|
||||
func TestOpus_VerifyOperator_NotSupervisor(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
e := c.Executor
|
||||
|
||||
acc := e.NewAccount(t)
|
||||
invoker := c.WithSigners(acc)
|
||||
|
||||
// Should fail - not supervisor
|
||||
invoker.InvokeFail(t, "caller is not an authorized supervisor", "verifyOperator", acc.ScriptHash())
|
||||
}
|
||||
|
||||
// Note: suspendOperator method is not currently implemented. Operators can be managed
|
||||
// through their linked Vita status.
|
||||
|
||||
// TestOpus_RegisterWorker_NoOperator tests that registering worker without operator fails.
|
||||
func TestOpus_RegisterWorker_NoOperator(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
e := c.Executor
|
||||
|
||||
acc := e.NewAccount(t)
|
||||
invoker := c.WithSigners(acc)
|
||||
|
||||
modelHash := hash.Sha256([]byte("model")).BytesBE()
|
||||
|
||||
// Should fail - no operator registered (registerWorker takes: name, description, workerType, modelHash)
|
||||
invoker.InvokeFail(t, "operator profile not found", "registerWorker",
|
||||
"TestWorker", "Test AI Worker", int64(0), modelHash)
|
||||
}
|
||||
|
||||
// TestOpus_SuspendWorker_NotSupervisor tests that non-supervisor cannot suspend worker.
|
||||
func TestOpus_SuspendWorker_NotSupervisor(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
e := c.Executor
|
||||
|
||||
acc := e.NewAccount(t)
|
||||
invoker := c.WithSigners(acc)
|
||||
|
||||
// Should fail - not supervisor (checked before worker existence)
|
||||
invoker.InvokeFail(t, "caller is not an authorized supervisor", "suspendWorker", int64(999), "suspension reason")
|
||||
}
|
||||
|
||||
// TestOpus_AssignTask_WorkerNotFound tests that assigning task to non-existent worker fails.
|
||||
func TestOpus_AssignTask_WorkerNotFound(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
e := c.Executor
|
||||
|
||||
acc := e.NewAccount(t)
|
||||
invoker := c.WithSigners(acc)
|
||||
|
||||
// Should fail - worker not found
|
||||
invoker.InvokeFail(t, "worker not found", "assignTask",
|
||||
int64(999), "task-123", "Test Task", int64(1000))
|
||||
}
|
||||
|
||||
// TestOpus_CompleteTask_TaskNotFound tests that completing non-existent task fails.
|
||||
func TestOpus_CompleteTask_TaskNotFound(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
e := c.Executor
|
||||
|
||||
acc := e.NewAccount(t)
|
||||
invoker := c.WithSigners(acc)
|
||||
|
||||
resultHash := hash.Sha256([]byte("result")).BytesBE()
|
||||
|
||||
// Should fail - task not found
|
||||
invoker.InvokeFail(t, "task not found", "completeTask", int64(999), resultHash, int64(500))
|
||||
}
|
||||
|
||||
// TestOpus_AddCapability_WorkerNotFound tests that adding capability to non-existent worker fails.
|
||||
func TestOpus_AddCapability_WorkerNotFound(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
e := c.Executor
|
||||
|
||||
acc := e.NewAccount(t)
|
||||
invoker := c.WithSigners(acc)
|
||||
|
||||
// Should fail - worker not found (before checking supervisor)
|
||||
invoker.InvokeFail(t, "AI worker not found", "addCapability",
|
||||
int64(999), "language_model", int64(3), "Test certification")
|
||||
}
|
||||
|
||||
// TestOpus_RegisterOperatorWithVita tests operator registration with a valid Vita.
|
||||
func TestOpus_RegisterOperatorWithVita(t *testing.T) {
|
||||
c := newOpusClient(t)
|
||||
e := c.Executor
|
||||
|
||||
// Register Vita first
|
||||
vitaHash := e.NativeHash(t, nativenames.Vita)
|
||||
acc := e.NewAccount(t)
|
||||
vitaInvoker := e.NewInvoker(vitaHash, acc)
|
||||
|
||||
owner := acc.ScriptHash()
|
||||
personHash := hash.Sha256(owner.BytesBE()).BytesBE()
|
||||
isEntity := false
|
||||
recoveryHash := hash.Sha256([]byte("recovery")).BytesBE()
|
||||
|
||||
// Register Vita token
|
||||
vitaInvoker.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
|
||||
require.Equal(t, 1, len(stack))
|
||||
_, ok := stack[0].Value().([]byte)
|
||||
require.True(t, ok, "expected ByteArray result")
|
||||
}, "register", owner.BytesBE(), personHash, isEntity, recoveryHash)
|
||||
|
||||
// Now register operator (only takes owner as parameter)
|
||||
opusInvoker := c.WithSigners(acc)
|
||||
opusInvoker.Invoke(t, true, "registerOperator", owner.BytesBE())
|
||||
|
||||
// Verify operator exists
|
||||
opusInvoker.InvokeAndCheck(t, func(t testing.TB, stack []stackitem.Item) {
|
||||
require.Equal(t, 1, len(stack))
|
||||
arr, ok := stack[0].Value().([]stackitem.Item)
|
||||
require.True(t, ok, "expected array result for existing operator")
|
||||
require.GreaterOrEqual(t, len(arr), 9) // OperatorProfile has 9 fields
|
||||
}, "getOperator", owner.BytesBE())
|
||||
|
||||
// Verify total operators increased
|
||||
c.Invoke(t, 1, "getTotalOperators")
|
||||
}
|
||||
|
|
@ -45,4 +45,12 @@ var (
|
|||
Eligere = util.Uint160{0x1, 0x94, 0x73, 0x8e, 0xab, 0x6b, 0xc5, 0xa0, 0xff, 0xab, 0xe0, 0x2a, 0xce, 0xea, 0xd7, 0xb3, 0xa8, 0xe5, 0x7, 0x40}
|
||||
// Scire is a hash of native Scire contract.
|
||||
Scire = util.Uint160{0x9f, 0x7, 0x16, 0xd4, 0xd6, 0xb8, 0xae, 0x2d, 0x58, 0x42, 0x94, 0xf8, 0x92, 0x62, 0x5d, 0x8e, 0x63, 0xa0, 0xde, 0x3}
|
||||
// Salus is a hash of native Salus contract.
|
||||
Salus = util.Uint160{0x91, 0x6e, 0x6a, 0xf6, 0x70, 0x7b, 0x91, 0x75, 0x9f, 0xbd, 0xff, 0xdb, 0x25, 0xe6, 0xee, 0xf9, 0x4f, 0x20, 0x88, 0xc8}
|
||||
// Sese is a hash of native Sese contract.
|
||||
Sese = util.Uint160{0x16, 0x99, 0x28, 0x39, 0x2, 0xfe, 0x12, 0x60, 0xf3, 0xe, 0x4b, 0x2b, 0xf7, 0x44, 0x19, 0xc4, 0x7d, 0x24, 0xfd, 0x48}
|
||||
// Tribute is a hash of native Tribute contract.
|
||||
Tribute = util.Uint160{0x35, 0x9b, 0xbf, 0x51, 0xb5, 0xe3, 0x73, 0x6d, 0x52, 0xad, 0x80, 0xb0, 0x28, 0x4f, 0x22, 0x8f, 0x9, 0xaf, 0x49, 0x1e}
|
||||
// Opus is a hash of native Opus contract.
|
||||
Opus = util.Uint160{0xf5, 0x22, 0x73, 0x17, 0x98, 0xab, 0xfc, 0x4d, 0x7c, 0x3a, 0x51, 0x8, 0x47, 0xc7, 0xe5, 0xe4, 0x6, 0x96, 0xb6, 0xfd}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -43,4 +43,12 @@ const (
|
|||
Eligere int32 = -17
|
||||
// Scire is an ID of native Scire contract.
|
||||
Scire int32 = -18
|
||||
// Salus is an ID of native Salus contract.
|
||||
Salus int32 = -19
|
||||
// Sese is an ID of native Sese contract.
|
||||
Sese int32 = -20
|
||||
// Tribute is an ID of native Tribute contract.
|
||||
Tribute int32 = -21
|
||||
// Opus is an ID of native Opus contract.
|
||||
Opus int32 = -22
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ const (
|
|||
Lex = "Lex"
|
||||
Eligere = "Eligere"
|
||||
Scire = "Scire"
|
||||
Salus = "Salus"
|
||||
Sese = "Sese"
|
||||
Tribute = "Tribute"
|
||||
Opus = "Opus"
|
||||
)
|
||||
|
||||
// All contains the list of all native contract names ordered by the contract ID.
|
||||
|
|
@ -42,6 +46,10 @@ var All = []string{
|
|||
Lex,
|
||||
Eligere,
|
||||
Scire,
|
||||
Salus,
|
||||
Sese,
|
||||
Tribute,
|
||||
Opus,
|
||||
}
|
||||
|
||||
// IsValid checks if the name is a valid native contract's name.
|
||||
|
|
@ -63,5 +71,9 @@ func IsValid(name string) bool {
|
|||
name == Federation ||
|
||||
name == Lex ||
|
||||
name == Eligere ||
|
||||
name == Scire
|
||||
name == Scire ||
|
||||
name == Salus ||
|
||||
name == Sese ||
|
||||
name == Tribute ||
|
||||
name == Opus
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,623 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/tutus-one/tutus-chain/pkg/util"
|
||||
"github.com/tutus-one/tutus-chain/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// AIWorkerStatus represents the status of an AI worker.
|
||||
type AIWorkerStatus uint8
|
||||
|
||||
const (
|
||||
// AIWorkerActive indicates an active AI worker.
|
||||
AIWorkerActive AIWorkerStatus = 0
|
||||
// AIWorkerSuspended indicates a suspended AI worker.
|
||||
AIWorkerSuspended AIWorkerStatus = 1
|
||||
// AIWorkerDecommissioned indicates a decommissioned AI worker.
|
||||
AIWorkerDecommissioned AIWorkerStatus = 2
|
||||
)
|
||||
|
||||
// TaskStatus represents the status of an AI task.
|
||||
type TaskStatus uint8
|
||||
|
||||
const (
|
||||
// TaskAssigned indicates a task has been assigned.
|
||||
TaskAssigned TaskStatus = 0
|
||||
// TaskInProgress indicates a task is being worked on.
|
||||
TaskInProgress TaskStatus = 1
|
||||
// TaskCompleted indicates a task was completed successfully.
|
||||
TaskCompleted TaskStatus = 2
|
||||
// TaskFailed indicates a task failed.
|
||||
TaskFailed TaskStatus = 3
|
||||
// TaskCancelled indicates a task was cancelled.
|
||||
TaskCancelled TaskStatus = 4
|
||||
)
|
||||
|
||||
// CapabilityLevel represents the proficiency level of an AI capability.
|
||||
type CapabilityLevel uint8
|
||||
|
||||
const (
|
||||
// CapabilityBasic represents basic proficiency.
|
||||
CapabilityBasic CapabilityLevel = 0
|
||||
// CapabilityStandard represents standard proficiency.
|
||||
CapabilityStandard CapabilityLevel = 1
|
||||
// CapabilityAdvanced represents advanced proficiency.
|
||||
CapabilityAdvanced CapabilityLevel = 2
|
||||
// CapabilityExpert represents expert proficiency.
|
||||
CapabilityExpert CapabilityLevel = 3
|
||||
)
|
||||
|
||||
// WorkerType represents the type of AI worker.
|
||||
type WorkerType uint8
|
||||
|
||||
const (
|
||||
// WorkerTypeGeneral represents a general-purpose AI.
|
||||
WorkerTypeGeneral WorkerType = 0
|
||||
// WorkerTypeSpecialized represents a domain-specialized AI.
|
||||
WorkerTypeSpecialized WorkerType = 1
|
||||
// WorkerTypeAutonomous represents a fully autonomous AI agent.
|
||||
WorkerTypeAutonomous WorkerType = 2
|
||||
// WorkerTypeAssistive represents an AI that assists humans.
|
||||
WorkerTypeAssistive WorkerType = 3
|
||||
)
|
||||
|
||||
// AIWorker represents a registered AI worker in the Opus system.
|
||||
type AIWorker struct {
|
||||
ID uint64 // Unique AI worker ID
|
||||
Name string // Human-readable name
|
||||
Description string // Description of capabilities
|
||||
OperatorVitaID uint64 // Vita ID of the human/org operator
|
||||
Operator util.Uint160 // Operator's address
|
||||
WorkerType WorkerType // Type of AI worker
|
||||
ModelHash util.Uint256 // Hash of the AI model/system
|
||||
TributeRate uint32 // Tribute rate in basis points (e.g., 5000 = 50%)
|
||||
TotalTasksAssigned uint64 // Total tasks assigned
|
||||
TotalTasksCompleted uint64 // Total tasks completed
|
||||
TotalValueGenerated uint64 // Total value generated (in VTS)
|
||||
TotalTributePaid uint64 // Total tribute paid to society
|
||||
Status AIWorkerStatus // Worker status
|
||||
RegisteredAt uint32 // Block height when registered
|
||||
UpdatedAt uint32 // Block height of last update
|
||||
}
|
||||
|
||||
// ToStackItem implements stackitem.Convertible interface.
|
||||
func (w *AIWorker) ToStackItem() (stackitem.Item, error) {
|
||||
return stackitem.NewStruct([]stackitem.Item{
|
||||
stackitem.NewBigInteger(big.NewInt(int64(w.ID))),
|
||||
stackitem.NewByteArray([]byte(w.Name)),
|
||||
stackitem.NewByteArray([]byte(w.Description)),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(w.OperatorVitaID))),
|
||||
stackitem.NewByteArray(w.Operator.BytesBE()),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(w.WorkerType))),
|
||||
stackitem.NewByteArray(w.ModelHash.BytesBE()),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(w.TributeRate))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(w.TotalTasksAssigned))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(w.TotalTasksCompleted))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(w.TotalValueGenerated))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(w.TotalTributePaid))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(w.Status))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(w.RegisteredAt))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(w.UpdatedAt))),
|
||||
}), nil
|
||||
}
|
||||
|
||||
// FromStackItem implements stackitem.Convertible interface.
|
||||
func (w *AIWorker) FromStackItem(item stackitem.Item) error {
|
||||
items, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return errors.New("not a struct")
|
||||
}
|
||||
if len(items) != 15 {
|
||||
return fmt.Errorf("wrong number of elements: expected 15, got %d", len(items))
|
||||
}
|
||||
|
||||
id, err := items[0].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid id: %w", err)
|
||||
}
|
||||
w.ID = id.Uint64()
|
||||
|
||||
name, err := items[1].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid name: %w", err)
|
||||
}
|
||||
w.Name = string(name)
|
||||
|
||||
description, err := items[2].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid description: %w", err)
|
||||
}
|
||||
w.Description = string(description)
|
||||
|
||||
operatorVitaID, err := items[3].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid operatorVitaID: %w", err)
|
||||
}
|
||||
w.OperatorVitaID = operatorVitaID.Uint64()
|
||||
|
||||
operator, err := items[4].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid operator: %w", err)
|
||||
}
|
||||
w.Operator, err = util.Uint160DecodeBytesBE(operator)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid operator address: %w", err)
|
||||
}
|
||||
|
||||
workerType, err := items[5].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid workerType: %w", err)
|
||||
}
|
||||
w.WorkerType = WorkerType(workerType.Uint64())
|
||||
|
||||
modelHash, err := items[6].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid modelHash: %w", err)
|
||||
}
|
||||
w.ModelHash, err = util.Uint256DecodeBytesBE(modelHash)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid modelHash value: %w", err)
|
||||
}
|
||||
|
||||
tributeRate, err := items[7].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid tributeRate: %w", err)
|
||||
}
|
||||
w.TributeRate = uint32(tributeRate.Uint64())
|
||||
|
||||
tasksAssigned, err := items[8].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid totalTasksAssigned: %w", err)
|
||||
}
|
||||
w.TotalTasksAssigned = tasksAssigned.Uint64()
|
||||
|
||||
tasksCompleted, err := items[9].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid totalTasksCompleted: %w", err)
|
||||
}
|
||||
w.TotalTasksCompleted = tasksCompleted.Uint64()
|
||||
|
||||
valueGenerated, err := items[10].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid totalValueGenerated: %w", err)
|
||||
}
|
||||
w.TotalValueGenerated = valueGenerated.Uint64()
|
||||
|
||||
tributePaid, err := items[11].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid totalTributePaid: %w", err)
|
||||
}
|
||||
w.TotalTributePaid = tributePaid.Uint64()
|
||||
|
||||
status, err := items[12].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid status: %w", err)
|
||||
}
|
||||
w.Status = AIWorkerStatus(status.Uint64())
|
||||
|
||||
registeredAt, err := items[13].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid registeredAt: %w", err)
|
||||
}
|
||||
w.RegisteredAt = uint32(registeredAt.Uint64())
|
||||
|
||||
updatedAt, err := items[14].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid updatedAt: %w", err)
|
||||
}
|
||||
w.UpdatedAt = uint32(updatedAt.Uint64())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AITask represents a task assigned to an AI worker.
|
||||
type AITask struct {
|
||||
ID uint64 // Unique task ID
|
||||
WorkerID uint64 // AI worker ID
|
||||
RequesterVitaID uint64 // Vita ID of the requester (0 = system task)
|
||||
Requester util.Uint160 // Requester's address
|
||||
TaskType string // Type/category of task
|
||||
Description string // Task description
|
||||
ValueOffered uint64 // VTS value offered for task
|
||||
ValueCompleted uint64 // Actual value upon completion
|
||||
TributePaid uint64 // Tribute paid from this task
|
||||
ResultHash util.Uint256 // Hash of task result/output
|
||||
Status TaskStatus // Task status
|
||||
AssignedAt uint32 // Block height when assigned
|
||||
CompletedAt uint32 // Block height when completed (0 = incomplete)
|
||||
}
|
||||
|
||||
// ToStackItem implements stackitem.Convertible interface.
|
||||
func (t *AITask) ToStackItem() (stackitem.Item, error) {
|
||||
return stackitem.NewStruct([]stackitem.Item{
|
||||
stackitem.NewBigInteger(big.NewInt(int64(t.ID))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(t.WorkerID))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(t.RequesterVitaID))),
|
||||
stackitem.NewByteArray(t.Requester.BytesBE()),
|
||||
stackitem.NewByteArray([]byte(t.TaskType)),
|
||||
stackitem.NewByteArray([]byte(t.Description)),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(t.ValueOffered))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(t.ValueCompleted))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(t.TributePaid))),
|
||||
stackitem.NewByteArray(t.ResultHash.BytesBE()),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(t.Status))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(t.AssignedAt))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(t.CompletedAt))),
|
||||
}), nil
|
||||
}
|
||||
|
||||
// FromStackItem implements stackitem.Convertible interface.
|
||||
func (t *AITask) FromStackItem(item stackitem.Item) error {
|
||||
items, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return errors.New("not a struct")
|
||||
}
|
||||
if len(items) != 13 {
|
||||
return fmt.Errorf("wrong number of elements: expected 13, got %d", len(items))
|
||||
}
|
||||
|
||||
id, err := items[0].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid id: %w", err)
|
||||
}
|
||||
t.ID = id.Uint64()
|
||||
|
||||
workerID, err := items[1].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid workerID: %w", err)
|
||||
}
|
||||
t.WorkerID = workerID.Uint64()
|
||||
|
||||
requesterVitaID, err := items[2].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid requesterVitaID: %w", err)
|
||||
}
|
||||
t.RequesterVitaID = requesterVitaID.Uint64()
|
||||
|
||||
requester, err := items[3].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid requester: %w", err)
|
||||
}
|
||||
t.Requester, err = util.Uint160DecodeBytesBE(requester)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid requester address: %w", err)
|
||||
}
|
||||
|
||||
taskType, err := items[4].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid taskType: %w", err)
|
||||
}
|
||||
t.TaskType = string(taskType)
|
||||
|
||||
description, err := items[5].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid description: %w", err)
|
||||
}
|
||||
t.Description = string(description)
|
||||
|
||||
valueOffered, err := items[6].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid valueOffered: %w", err)
|
||||
}
|
||||
t.ValueOffered = valueOffered.Uint64()
|
||||
|
||||
valueCompleted, err := items[7].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid valueCompleted: %w", err)
|
||||
}
|
||||
t.ValueCompleted = valueCompleted.Uint64()
|
||||
|
||||
tributePaid, err := items[8].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid tributePaid: %w", err)
|
||||
}
|
||||
t.TributePaid = tributePaid.Uint64()
|
||||
|
||||
resultHash, err := items[9].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid resultHash: %w", err)
|
||||
}
|
||||
t.ResultHash, err = util.Uint256DecodeBytesBE(resultHash)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid resultHash value: %w", err)
|
||||
}
|
||||
|
||||
status, err := items[10].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid status: %w", err)
|
||||
}
|
||||
t.Status = TaskStatus(status.Uint64())
|
||||
|
||||
assignedAt, err := items[11].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid assignedAt: %w", err)
|
||||
}
|
||||
t.AssignedAt = uint32(assignedAt.Uint64())
|
||||
|
||||
completedAt, err := items[12].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid completedAt: %w", err)
|
||||
}
|
||||
t.CompletedAt = uint32(completedAt.Uint64())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AICapability represents a certified capability of an AI worker.
|
||||
type AICapability struct {
|
||||
ID uint64 // Unique capability ID
|
||||
WorkerID uint64 // AI worker ID
|
||||
Name string // Capability name
|
||||
Category string // Capability category
|
||||
Level CapabilityLevel // Proficiency level
|
||||
CertifiedBy util.Uint160 // Certifier's address
|
||||
CertifiedAt uint32 // Block height when certified
|
||||
ExpiresAt uint32 // Expiration block (0 = never)
|
||||
IsVerified bool // Whether capability is verified
|
||||
}
|
||||
|
||||
// ToStackItem implements stackitem.Convertible interface.
|
||||
func (c *AICapability) ToStackItem() (stackitem.Item, error) {
|
||||
return stackitem.NewStruct([]stackitem.Item{
|
||||
stackitem.NewBigInteger(big.NewInt(int64(c.ID))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(c.WorkerID))),
|
||||
stackitem.NewByteArray([]byte(c.Name)),
|
||||
stackitem.NewByteArray([]byte(c.Category)),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(c.Level))),
|
||||
stackitem.NewByteArray(c.CertifiedBy.BytesBE()),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(c.CertifiedAt))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(c.ExpiresAt))),
|
||||
stackitem.NewBool(c.IsVerified),
|
||||
}), nil
|
||||
}
|
||||
|
||||
// FromStackItem implements stackitem.Convertible interface.
|
||||
func (c *AICapability) FromStackItem(item stackitem.Item) error {
|
||||
items, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return errors.New("not a struct")
|
||||
}
|
||||
if len(items) != 9 {
|
||||
return fmt.Errorf("wrong number of elements: expected 9, got %d", len(items))
|
||||
}
|
||||
|
||||
id, err := items[0].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid id: %w", err)
|
||||
}
|
||||
c.ID = id.Uint64()
|
||||
|
||||
workerID, err := items[1].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid workerID: %w", err)
|
||||
}
|
||||
c.WorkerID = workerID.Uint64()
|
||||
|
||||
name, err := items[2].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid name: %w", err)
|
||||
}
|
||||
c.Name = string(name)
|
||||
|
||||
category, err := items[3].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid category: %w", err)
|
||||
}
|
||||
c.Category = string(category)
|
||||
|
||||
level, err := items[4].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid level: %w", err)
|
||||
}
|
||||
c.Level = CapabilityLevel(level.Uint64())
|
||||
|
||||
certifiedBy, err := items[5].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid certifiedBy: %w", err)
|
||||
}
|
||||
c.CertifiedBy, err = util.Uint160DecodeBytesBE(certifiedBy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid certifiedBy address: %w", err)
|
||||
}
|
||||
|
||||
certifiedAt, err := items[6].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid certifiedAt: %w", err)
|
||||
}
|
||||
c.CertifiedAt = uint32(certifiedAt.Uint64())
|
||||
|
||||
expiresAt, err := items[7].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid expiresAt: %w", err)
|
||||
}
|
||||
c.ExpiresAt = uint32(expiresAt.Uint64())
|
||||
|
||||
isVerified, err := items[8].TryBool()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid isVerified: %w", err)
|
||||
}
|
||||
c.IsVerified = isVerified
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// OperatorProfile represents an AI operator's profile (human/org that deploys AI).
|
||||
type OperatorProfile struct {
|
||||
VitaID uint64 // Operator's Vita ID
|
||||
Owner util.Uint160 // Operator's address
|
||||
TotalWorkersOwned uint64 // Number of AI workers owned
|
||||
TotalTributePaid uint64 // Total tribute paid by all workers
|
||||
TotalValueGenerated uint64 // Total value generated by all workers
|
||||
ReputationScore uint32 // Reputation score (0-10000 basis points)
|
||||
IsVerified bool // Whether operator is verified
|
||||
CreatedAt uint32 // Block height when created
|
||||
UpdatedAt uint32 // Block height of last update
|
||||
}
|
||||
|
||||
// ToStackItem implements stackitem.Convertible interface.
|
||||
func (p *OperatorProfile) ToStackItem() (stackitem.Item, error) {
|
||||
return stackitem.NewStruct([]stackitem.Item{
|
||||
stackitem.NewBigInteger(big.NewInt(int64(p.VitaID))),
|
||||
stackitem.NewByteArray(p.Owner.BytesBE()),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(p.TotalWorkersOwned))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(p.TotalTributePaid))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(p.TotalValueGenerated))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(p.ReputationScore))),
|
||||
stackitem.NewBool(p.IsVerified),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(p.CreatedAt))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(p.UpdatedAt))),
|
||||
}), nil
|
||||
}
|
||||
|
||||
// FromStackItem implements stackitem.Convertible interface.
|
||||
func (p *OperatorProfile) FromStackItem(item stackitem.Item) error {
|
||||
items, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return errors.New("not a struct")
|
||||
}
|
||||
if len(items) != 9 {
|
||||
return fmt.Errorf("wrong number of elements: expected 9, got %d", len(items))
|
||||
}
|
||||
|
||||
vitaID, err := items[0].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid vitaID: %w", err)
|
||||
}
|
||||
p.VitaID = vitaID.Uint64()
|
||||
|
||||
owner, err := items[1].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid owner: %w", err)
|
||||
}
|
||||
p.Owner, err = util.Uint160DecodeBytesBE(owner)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid owner address: %w", err)
|
||||
}
|
||||
|
||||
totalWorkers, err := items[2].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid totalWorkersOwned: %w", err)
|
||||
}
|
||||
p.TotalWorkersOwned = totalWorkers.Uint64()
|
||||
|
||||
tributePaid, err := items[3].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid totalTributePaid: %w", err)
|
||||
}
|
||||
p.TotalTributePaid = tributePaid.Uint64()
|
||||
|
||||
valueGenerated, err := items[4].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid totalValueGenerated: %w", err)
|
||||
}
|
||||
p.TotalValueGenerated = valueGenerated.Uint64()
|
||||
|
||||
reputationScore, err := items[5].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid reputationScore: %w", err)
|
||||
}
|
||||
p.ReputationScore = uint32(reputationScore.Uint64())
|
||||
|
||||
isVerified, err := items[6].TryBool()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid isVerified: %w", err)
|
||||
}
|
||||
p.IsVerified = isVerified
|
||||
|
||||
createdAt, err := items[7].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid createdAt: %w", err)
|
||||
}
|
||||
p.CreatedAt = uint32(createdAt.Uint64())
|
||||
|
||||
updatedAt, err := items[8].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid updatedAt: %w", err)
|
||||
}
|
||||
p.UpdatedAt = uint32(updatedAt.Uint64())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// OpusConfig represents configurable parameters for the Opus contract.
|
||||
type OpusConfig struct {
|
||||
MinTributeRate uint32 // Minimum tribute rate (basis points)
|
||||
MaxTributeRate uint32 // Maximum tribute rate (basis points)
|
||||
DefaultTributeRate uint32 // Default tribute rate for new workers
|
||||
RegistrationFee uint64 // VTS fee to register an AI worker
|
||||
TaskCompletionMinimum uint64 // Minimum value for task completion
|
||||
VerificationRequired bool // Whether operator verification is required
|
||||
MaxWorkersPerOperator uint64 // Maximum AI workers per operator (0 = unlimited)
|
||||
}
|
||||
|
||||
// ToStackItem implements stackitem.Convertible interface.
|
||||
func (c *OpusConfig) ToStackItem() (stackitem.Item, error) {
|
||||
return stackitem.NewStruct([]stackitem.Item{
|
||||
stackitem.NewBigInteger(big.NewInt(int64(c.MinTributeRate))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(c.MaxTributeRate))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(c.DefaultTributeRate))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(c.RegistrationFee))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(c.TaskCompletionMinimum))),
|
||||
stackitem.NewBool(c.VerificationRequired),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(c.MaxWorkersPerOperator))),
|
||||
}), nil
|
||||
}
|
||||
|
||||
// FromStackItem implements stackitem.Convertible interface.
|
||||
func (c *OpusConfig) FromStackItem(item stackitem.Item) error {
|
||||
items, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return errors.New("not a struct")
|
||||
}
|
||||
if len(items) != 7 {
|
||||
return fmt.Errorf("wrong number of elements: expected 7, got %d", len(items))
|
||||
}
|
||||
|
||||
minRate, err := items[0].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid minTributeRate: %w", err)
|
||||
}
|
||||
c.MinTributeRate = uint32(minRate.Uint64())
|
||||
|
||||
maxRate, err := items[1].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid maxTributeRate: %w", err)
|
||||
}
|
||||
c.MaxTributeRate = uint32(maxRate.Uint64())
|
||||
|
||||
defaultRate, err := items[2].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid defaultTributeRate: %w", err)
|
||||
}
|
||||
c.DefaultTributeRate = uint32(defaultRate.Uint64())
|
||||
|
||||
regFee, err := items[3].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid registrationFee: %w", err)
|
||||
}
|
||||
c.RegistrationFee = regFee.Uint64()
|
||||
|
||||
taskMin, err := items[4].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid taskCompletionMinimum: %w", err)
|
||||
}
|
||||
c.TaskCompletionMinimum = taskMin.Uint64()
|
||||
|
||||
verificationReq, err := items[5].TryBool()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid verificationRequired: %w", err)
|
||||
}
|
||||
c.VerificationRequired = verificationReq
|
||||
|
||||
maxWorkers, err := items[6].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid maxWorkersPerOperator: %w", err)
|
||||
}
|
||||
c.MaxWorkersPerOperator = maxWorkers.Uint64()
|
||||
|
||||
return nil
|
||||
}
|
||||
Loading…
Reference in New Issue