diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 43f444d..7336e01 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -221,6 +221,7 @@ type Blockchain struct { vita native.IVita federation native.IFederation treasury native.ITreasury + lex native.ILex extensible atomic.Value @@ -480,6 +481,10 @@ func NewBlockchain(s storage.Store, cfg config.Blockchain, log *zap.Logger, newN if err := validateNative(bc.treasury, nativeids.Treasury, nativenames.Treasury, nativehashes.Treasury); err != nil { return nil, err } + bc.lex = bc.contracts.Lex() + if err := validateNative(bc.lex, nativeids.Lex, nativenames.Lex, nativehashes.Lex); err != nil { + return nil, err + } bc.persistCond = sync.NewCond(&bc.lock) bc.gcBlockTimes, _ = lru.New[uint32, uint64](defaultBlockTimesCache) // Never errors for positive size diff --git a/pkg/core/native/contract.go b/pkg/core/native/contract.go index 8ebdb39..7b6fa1f 100644 --- a/pkg/core/native/contract.go +++ b/pkg/core/native/contract.go @@ -436,6 +436,12 @@ func NewDefaultContracts(cfg config.ProtocolConfiguration) []interop.Contract { lex.RoleRegistry = roleRegistry lex.Federation = federation + // Wire Lex into VTS for property rights enforcement + vts.Lex = lex + + // Wire Lex into Vita for liberty rights enforcement (due process) + vita.Lex = lex + // Wire GAS dependencies for Vita fee exemption gas.Vita = vita gas.Federation = federation diff --git a/pkg/core/native/vita.go b/pkg/core/native/vita.go index 1b8b27e..ea763f3 100644 --- a/pkg/core/native/vita.go +++ b/pkg/core/native/vita.go @@ -27,6 +27,7 @@ type Vita struct { interop.ContractMD NEO INEO RoleRegistry IRoleRegistry + Lex ILex } // VitaCache represents the cached state for Vita contract. @@ -724,6 +725,12 @@ func (v *Vita) suspend(ic *interop.Context, args []stackitem.Item) stackitem.Ite panic(ErrNotCommittee) } + // Require liberty restriction order from Lex (due process protection) + // Suspending a Vita is a restriction of liberty, which requires judicial authority + if v.Lex != nil && !v.Lex.IsRestrictedInternal(ic.DAO, owner, state.RightLiberty, ic.Block.Index) { + panic("liberty restriction order required via Lex (due process)") + } + // Get token token, err := v.getTokenByOwnerInternal(ic.DAO, owner) if err != nil { @@ -830,6 +837,12 @@ func (v *Vita) revoke(ic *interop.Context, args []stackitem.Item) stackitem.Item panic(ErrNotCommittee) } + // Require liberty restriction order from Lex (due process protection) + // Revoking a Vita is a permanent restriction of liberty, requiring judicial authority + if v.Lex != nil && !v.Lex.IsRestrictedInternal(ic.DAO, owner, state.RightLiberty, ic.Block.Index) { + panic("liberty restriction order required via Lex (due process)") + } + // Get token token, err := v.getTokenByOwnerInternal(ic.DAO, owner) if err != nil { diff --git a/pkg/core/native/vts.go b/pkg/core/native/vts.go index 37c2ad7..2ae068f 100644 --- a/pkg/core/native/vts.go +++ b/pkg/core/native/vts.go @@ -42,6 +42,7 @@ type VTS struct { NEO INEO RoleRegistry IRoleRegistry Vita IVita + Lex ILex symbol string decimals int64 @@ -518,6 +519,11 @@ func (v *VTS) transferUnrestricted(ic *interop.Context, from, to util.Uint160, a } } + // Check property rights via Lex (if Lex is wired) + if v.Lex != nil && !v.Lex.CheckPropertyRight(ic.DAO, from, ic.Block.Index) { + return errors.New("property rights restricted") + } + if amount.Sign() == 0 { v.emitTransfer(ic, &from, &to, amount) return nil @@ -940,6 +946,11 @@ func (v *VTS) spend(ic *interop.Context, args []stackitem.Item) stackitem.Item { } } + // Check property rights via Lex (if Lex is wired) + if v.Lex != nil && !v.Lex.CheckPropertyRight(ic.DAO, from, ic.Block.Index) { + panic("property rights restricted") + } + // Verify vendor is registered and active vendorInfo := v.getVendorInternal(ic.DAO, vendor) if vendorInfo == nil || !vendorInfo.Active {