411 lines
13 KiB
Go
411 lines
13 KiB
Go
package state
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
|
|
"github.com/tutus-one/tutus-chain/pkg/util"
|
|
"github.com/tutus-one/tutus-chain/pkg/vm/stackitem"
|
|
)
|
|
|
|
// LawCategory represents the hierarchical category of a law.
|
|
type LawCategory uint8
|
|
|
|
const (
|
|
// LawCategoryConstitutional represents immutable constitutional rights.
|
|
LawCategoryConstitutional LawCategory = 1
|
|
// LawCategoryFederal represents national/federal laws.
|
|
LawCategoryFederal LawCategory = 2
|
|
// LawCategoryRegional represents state/province laws.
|
|
LawCategoryRegional LawCategory = 3
|
|
// LawCategoryLocal represents municipal/local laws.
|
|
LawCategoryLocal LawCategory = 4
|
|
// LawCategoryAdministrative represents regulations and administrative rules.
|
|
LawCategoryAdministrative LawCategory = 5
|
|
)
|
|
|
|
// LawStatus represents the current status of a law.
|
|
type LawStatus uint8
|
|
|
|
const (
|
|
// LawStatusDraft indicates a proposed law not yet voted.
|
|
LawStatusDraft LawStatus = 0
|
|
// LawStatusActive indicates a law currently in force.
|
|
LawStatusActive LawStatus = 1
|
|
// LawStatusSuspended indicates a temporarily suspended law.
|
|
LawStatusSuspended LawStatus = 2
|
|
// LawStatusRepealed indicates a permanently removed law.
|
|
LawStatusRepealed LawStatus = 3
|
|
// LawStatusSuperseded indicates a law replaced by a newer one.
|
|
LawStatusSuperseded LawStatus = 4
|
|
)
|
|
|
|
// EnforcementType specifies how a law is enforced.
|
|
type EnforcementType uint8
|
|
|
|
const (
|
|
// EnforcementAutomatic means smart contracts block violations.
|
|
EnforcementAutomatic EnforcementType = 1
|
|
// EnforcementLogging means violations emit events but allow transaction.
|
|
EnforcementLogging EnforcementType = 2
|
|
// EnforcementAdvisory means non-binding guidance only.
|
|
EnforcementAdvisory EnforcementType = 3
|
|
)
|
|
|
|
// RestrictionType represents the type of rights restriction.
|
|
type RestrictionType uint8
|
|
|
|
const (
|
|
// RestrictionSuspend temporarily suspends a right.
|
|
RestrictionSuspend RestrictionType = 1
|
|
// RestrictionLimit limits a right (e.g., movement within area).
|
|
RestrictionLimit RestrictionType = 2
|
|
// RestrictionCondition makes a right conditional (e.g., probation).
|
|
RestrictionCondition RestrictionType = 3
|
|
)
|
|
|
|
// ConstitutionalRight IDs - these are immutable and built into the protocol.
|
|
const (
|
|
RightLife uint64 = 1 // Right to life
|
|
RightLiberty uint64 = 2 // Freedom from arbitrary detention
|
|
RightProperty uint64 = 3 // Right to own and transfer assets
|
|
RightEquality uint64 = 4 // Equal treatment under law
|
|
RightDueProcess uint64 = 5 // Fair legal proceedings
|
|
RightPrivacy uint64 = 6 // Privacy of personal data
|
|
RightExpression uint64 = 7 // Freedom of expression
|
|
RightAssembly uint64 = 8 // Freedom of assembly
|
|
RightMovement uint64 = 9 // Freedom of movement
|
|
RightEducation uint64 = 10 // Right to education
|
|
RightHealthcare uint64 = 11 // Right to healthcare
|
|
RightLabor uint64 = 12 // Right to fair labor
|
|
RightVote uint64 = 13 // Right to vote
|
|
RightAsylum uint64 = 14 // Right to seek asylum
|
|
|
|
// MaxConstitutionalRight is the highest constitutional right ID.
|
|
MaxConstitutionalRight uint64 = 14
|
|
)
|
|
|
|
// Law represents a law in the registry.
|
|
type Law struct {
|
|
ID uint64 // Unique law identifier
|
|
Name string // Human-readable name
|
|
ContentHash util.Uint256 // Hash of full law text (stored off-chain)
|
|
Category LawCategory // Constitutional, Federal, Regional, Local
|
|
Jurisdiction uint32 // Jurisdiction ID (0 = global)
|
|
ParentID uint64 // Parent law in hierarchy (0 = root)
|
|
EffectiveAt uint32 // Block height when law becomes active
|
|
ExpiresAt uint32 // Block height when law expires (0 = perpetual)
|
|
EnactedAt uint32 // Block height of enactment
|
|
EnactedBy util.Uint160 // Authority that enacted
|
|
Status LawStatus // Active, Suspended, Repealed, Superseded
|
|
SupersededBy uint64 // ID of law that replaced this one
|
|
RequiresVita bool // Whether law applies only to Vita holders
|
|
Enforcement EnforcementType // How law is enforced
|
|
}
|
|
|
|
// ToStackItem implements stackitem.Convertible interface.
|
|
func (l *Law) ToStackItem() (stackitem.Item, error) {
|
|
return stackitem.NewStruct([]stackitem.Item{
|
|
stackitem.NewBigInteger(big.NewInt(int64(l.ID))),
|
|
stackitem.NewByteArray([]byte(l.Name)),
|
|
stackitem.NewByteArray(l.ContentHash[:]),
|
|
stackitem.NewBigInteger(big.NewInt(int64(l.Category))),
|
|
stackitem.NewBigInteger(big.NewInt(int64(l.Jurisdiction))),
|
|
stackitem.NewBigInteger(big.NewInt(int64(l.ParentID))),
|
|
stackitem.NewBigInteger(big.NewInt(int64(l.EffectiveAt))),
|
|
stackitem.NewBigInteger(big.NewInt(int64(l.ExpiresAt))),
|
|
stackitem.NewBigInteger(big.NewInt(int64(l.EnactedAt))),
|
|
stackitem.NewByteArray(l.EnactedBy.BytesBE()),
|
|
stackitem.NewBigInteger(big.NewInt(int64(l.Status))),
|
|
stackitem.NewBigInteger(big.NewInt(int64(l.SupersededBy))),
|
|
stackitem.NewBool(l.RequiresVita),
|
|
stackitem.NewBigInteger(big.NewInt(int64(l.Enforcement))),
|
|
}), nil
|
|
}
|
|
|
|
// FromStackItem implements stackitem.Convertible interface.
|
|
func (l *Law) FromStackItem(item stackitem.Item) error {
|
|
items, ok := item.Value().([]stackitem.Item)
|
|
if !ok {
|
|
return errors.New("not a struct")
|
|
}
|
|
if len(items) != 14 {
|
|
return fmt.Errorf("wrong number of elements: expected 14, got %d", len(items))
|
|
}
|
|
|
|
id, err := items[0].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid ID: %w", err)
|
|
}
|
|
l.ID = id.Uint64()
|
|
|
|
name, err := items[1].TryBytes()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid Name: %w", err)
|
|
}
|
|
l.Name = string(name)
|
|
|
|
contentHash, err := items[2].TryBytes()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid ContentHash: %w", err)
|
|
}
|
|
if len(contentHash) == 32 {
|
|
copy(l.ContentHash[:], contentHash)
|
|
}
|
|
|
|
category, err := items[3].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid Category: %w", err)
|
|
}
|
|
l.Category = LawCategory(category.Uint64())
|
|
|
|
jurisdiction, err := items[4].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid Jurisdiction: %w", err)
|
|
}
|
|
l.Jurisdiction = uint32(jurisdiction.Uint64())
|
|
|
|
parentID, err := items[5].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid ParentID: %w", err)
|
|
}
|
|
l.ParentID = parentID.Uint64()
|
|
|
|
effectiveAt, err := items[6].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid EffectiveAt: %w", err)
|
|
}
|
|
l.EffectiveAt = uint32(effectiveAt.Uint64())
|
|
|
|
expiresAt, err := items[7].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid ExpiresAt: %w", err)
|
|
}
|
|
l.ExpiresAt = uint32(expiresAt.Uint64())
|
|
|
|
enactedAt, err := items[8].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid EnactedAt: %w", err)
|
|
}
|
|
l.EnactedAt = uint32(enactedAt.Uint64())
|
|
|
|
enactedBy, err := items[9].TryBytes()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid EnactedBy: %w", err)
|
|
}
|
|
l.EnactedBy, err = util.Uint160DecodeBytesBE(enactedBy)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid EnactedBy address: %w", err)
|
|
}
|
|
|
|
status, err := items[10].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid Status: %w", err)
|
|
}
|
|
l.Status = LawStatus(status.Uint64())
|
|
|
|
supersededBy, err := items[11].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid SupersededBy: %w", err)
|
|
}
|
|
l.SupersededBy = supersededBy.Uint64()
|
|
|
|
requiresVita, err := items[12].TryBool()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid RequiresVita: %w", err)
|
|
}
|
|
l.RequiresVita = requiresVita
|
|
|
|
enforcement, err := items[13].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid Enforcement: %w", err)
|
|
}
|
|
l.Enforcement = EnforcementType(enforcement.Uint64())
|
|
|
|
return nil
|
|
}
|
|
|
|
// Bytes serializes the Law to bytes.
|
|
func (l *Law) Bytes() []byte {
|
|
item, _ := l.ToStackItem()
|
|
data, _ := stackitem.Serialize(item)
|
|
return data
|
|
}
|
|
|
|
// LawFromBytes deserializes a Law from bytes.
|
|
func LawFromBytes(data []byte) (*Law, error) {
|
|
item, err := stackitem.Deserialize(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
l := &Law{}
|
|
if err := l.FromStackItem(item); err != nil {
|
|
return nil, err
|
|
}
|
|
return l, nil
|
|
}
|
|
|
|
// RightsRestriction represents a restriction on a constitutional right.
|
|
type RightsRestriction struct {
|
|
Subject util.Uint160 // Who is restricted
|
|
RightID uint64 // Which right is restricted
|
|
RestrictionType RestrictionType // Type of restriction
|
|
IssuedBy util.Uint160 // Authority that issued
|
|
IssuedAt uint32 // Block height when issued
|
|
ExpiresAt uint32 // When restriction ends (must be set)
|
|
Reason string // Legal basis
|
|
CaseID util.Uint256 // Associated legal case (required for due process)
|
|
}
|
|
|
|
// ToStackItem implements stackitem.Convertible interface.
|
|
func (r *RightsRestriction) ToStackItem() (stackitem.Item, error) {
|
|
return stackitem.NewStruct([]stackitem.Item{
|
|
stackitem.NewByteArray(r.Subject.BytesBE()),
|
|
stackitem.NewBigInteger(big.NewInt(int64(r.RightID))),
|
|
stackitem.NewBigInteger(big.NewInt(int64(r.RestrictionType))),
|
|
stackitem.NewByteArray(r.IssuedBy.BytesBE()),
|
|
stackitem.NewBigInteger(big.NewInt(int64(r.IssuedAt))),
|
|
stackitem.NewBigInteger(big.NewInt(int64(r.ExpiresAt))),
|
|
stackitem.NewByteArray([]byte(r.Reason)),
|
|
stackitem.NewByteArray(r.CaseID[:]),
|
|
}), nil
|
|
}
|
|
|
|
// FromStackItem implements stackitem.Convertible interface.
|
|
func (r *RightsRestriction) FromStackItem(item stackitem.Item) error {
|
|
items, ok := item.Value().([]stackitem.Item)
|
|
if !ok {
|
|
return errors.New("not a struct")
|
|
}
|
|
if len(items) != 8 {
|
|
return fmt.Errorf("wrong number of elements: expected 8, got %d", len(items))
|
|
}
|
|
|
|
subject, err := items[0].TryBytes()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid Subject: %w", err)
|
|
}
|
|
r.Subject, err = util.Uint160DecodeBytesBE(subject)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid Subject address: %w", err)
|
|
}
|
|
|
|
rightID, err := items[1].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid RightID: %w", err)
|
|
}
|
|
r.RightID = rightID.Uint64()
|
|
|
|
restrictionType, err := items[2].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid RestrictionType: %w", err)
|
|
}
|
|
r.RestrictionType = RestrictionType(restrictionType.Uint64())
|
|
|
|
issuedBy, err := items[3].TryBytes()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid IssuedBy: %w", err)
|
|
}
|
|
r.IssuedBy, err = util.Uint160DecodeBytesBE(issuedBy)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid IssuedBy address: %w", err)
|
|
}
|
|
|
|
issuedAt, err := items[4].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid IssuedAt: %w", err)
|
|
}
|
|
r.IssuedAt = uint32(issuedAt.Uint64())
|
|
|
|
expiresAt, err := items[5].TryInteger()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid ExpiresAt: %w", err)
|
|
}
|
|
r.ExpiresAt = uint32(expiresAt.Uint64())
|
|
|
|
reason, err := items[6].TryBytes()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid Reason: %w", err)
|
|
}
|
|
r.Reason = string(reason)
|
|
|
|
caseID, err := items[7].TryBytes()
|
|
if err != nil {
|
|
return fmt.Errorf("invalid CaseID: %w", err)
|
|
}
|
|
if len(caseID) == 32 {
|
|
copy(r.CaseID[:], caseID)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Bytes serializes the RightsRestriction to bytes.
|
|
func (r *RightsRestriction) Bytes() []byte {
|
|
item, _ := r.ToStackItem()
|
|
data, _ := stackitem.Serialize(item)
|
|
return data
|
|
}
|
|
|
|
// RightsRestrictionFromBytes deserializes a RightsRestriction from bytes.
|
|
func RightsRestrictionFromBytes(data []byte) (*RightsRestriction, error) {
|
|
item, err := stackitem.Deserialize(data)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
r := &RightsRestriction{}
|
|
if err := r.FromStackItem(item); err != nil {
|
|
return nil, err
|
|
}
|
|
return r, nil
|
|
}
|
|
|
|
// IsExpired returns true if the restriction has expired.
|
|
func (r *RightsRestriction) IsExpired(currentBlock uint32) bool {
|
|
return r.ExpiresAt != 0 && r.ExpiresAt <= currentBlock
|
|
}
|
|
|
|
// ConstitutionalRight represents an immutable constitutional right.
|
|
type ConstitutionalRight struct {
|
|
ID uint64 // Right ID (1-14)
|
|
Name string // Human-readable name
|
|
Description string // Description of the right
|
|
Enforcement EnforcementType // How right is enforced
|
|
}
|
|
|
|
// GetConstitutionalRights returns all 14 constitutional rights.
|
|
// These are hardcoded and immutable.
|
|
func GetConstitutionalRights() []ConstitutionalRight {
|
|
return []ConstitutionalRight{
|
|
{RightLife, "Life", "Protection from arbitrary death", EnforcementAutomatic},
|
|
{RightLiberty, "Liberty", "Freedom from arbitrary detention", EnforcementAutomatic},
|
|
{RightProperty, "Property", "Right to own and transfer assets", EnforcementAutomatic},
|
|
{RightEquality, "Equality", "Equal treatment under law", EnforcementAutomatic},
|
|
{RightDueProcess, "DueProcess", "Fair legal proceedings before restriction", EnforcementAutomatic},
|
|
{RightPrivacy, "Privacy", "Privacy of personal data", EnforcementAutomatic},
|
|
{RightExpression, "Expression", "Freedom of expression", EnforcementLogging},
|
|
{RightAssembly, "Assembly", "Freedom of assembly", EnforcementLogging},
|
|
{RightMovement, "Movement", "Freedom of movement", EnforcementAutomatic},
|
|
{RightEducation, "Education", "Right to education", EnforcementLogging},
|
|
{RightHealthcare, "Healthcare", "Right to healthcare", EnforcementLogging},
|
|
{RightLabor, "Labor", "Right to fair labor conditions", EnforcementLogging},
|
|
{RightVote, "Vote", "Right to participate in democracy", EnforcementAutomatic},
|
|
{RightAsylum, "Asylum", "Right to seek protection from persecution", EnforcementAutomatic},
|
|
}
|
|
}
|
|
|
|
// GetConstitutionalRight returns a specific constitutional right by ID.
|
|
func GetConstitutionalRight(id uint64) *ConstitutionalRight {
|
|
if id < 1 || id > MaxConstitutionalRight {
|
|
return nil
|
|
}
|
|
rights := GetConstitutionalRights()
|
|
return &rights[id-1]
|
|
}
|
|
|
|
// IsConstitutionalRight returns true if the right ID is a constitutional right.
|
|
func IsConstitutionalRight(id uint64) bool {
|
|
return id >= 1 && id <= MaxConstitutionalRight
|
|
}
|