Add Palam native contract for programmed transparency
Implement transparent ledger infrastructure for accountable governance: - TransactionFlow tracking: Multi-party flows with complete audit trails - Full lifecycle: Initiation -> Intermediate steps -> Completion - Participant verification via Vita token (one-person-one-identity) - Immutable flow records with timestamp chains - Encrypted Payload System: Role-based access to sensitive data - Payloads encrypted per-role (Consumer, Merchant, Bank, etc.) - Keys distributed to authorized parties only - Supports judicial declassification process - Declassification Requests: Due process for accessing protected data - Judicial authority required (RolePalamJudge = 26) - Multi-party approval workflow - Configurable approval thresholds and expiry - Audit Log System: Complete transparency for oversight - All operations logged with actor attribution - Auditor access via RolePalamAuditor (25) - Immutable chronological records - Cross-contract integration: - Vita: Identity verification for participants - RoleRegistry: Role-based authorization - Lex: Rights enforcement for privacy protections Latin naming: Palam = "openly/publicly" - reflecting the contract's purpose of enabling transparent governance while protecting legitimate privacy through programmed disclosure rules. Contract ID: -23 🤖 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
9a57598c91
commit
8ef02620ea
|
|
@ -292,6 +292,17 @@ type (
|
|||
// Address returns the contract's script hash.
|
||||
Address() util.Uint160
|
||||
}
|
||||
|
||||
// IPalam provides programmed transparency with role-based encrypted payloads.
|
||||
IPalam interface {
|
||||
interop.Contract
|
||||
// GetFlowInternal returns a flow by ID.
|
||||
GetFlowInternal(d *dao.Simple, flowID util.Uint256) *state.Flow
|
||||
// HasDeclassifyGrant checks if requester has declassify grant for a flow.
|
||||
HasDeclassifyGrant(d *dao.Simple, flowID util.Uint256, requester util.Uint160) bool
|
||||
// Address returns the contract's script hash.
|
||||
Address() util.Uint160
|
||||
}
|
||||
)
|
||||
|
||||
// Contracts is a convenient wrapper around an arbitrary set of native contracts
|
||||
|
|
@ -479,6 +490,12 @@ func (cs *Contracts) Opus() IOpus {
|
|||
return cs.ByName(nativenames.Opus).(IOpus)
|
||||
}
|
||||
|
||||
// Palam returns native IPalam contract implementation. It panics if
|
||||
// there's no contract with proper name in cs.
|
||||
func (cs *Contracts) Palam() IPalam {
|
||||
return cs.ByName(nativenames.Palam).(IPalam)
|
||||
}
|
||||
|
||||
// NewDefaultContracts returns a new set of default native contracts.
|
||||
func NewDefaultContracts(cfg config.ProtocolConfiguration) []interop.Contract {
|
||||
mgmt := NewManagement()
|
||||
|
|
@ -610,6 +627,13 @@ func NewDefaultContracts(cfg config.ProtocolConfiguration) []interop.Contract {
|
|||
opus.Lex = lex
|
||||
opus.Treasury = treasury
|
||||
|
||||
// Create Palam (Programmed Transparency) contract
|
||||
palam := NewPalam()
|
||||
palam.NEO = neo
|
||||
palam.Vita = vita
|
||||
palam.RoleRegistry = roleRegistry
|
||||
palam.Lex = lex
|
||||
|
||||
return []interop.Contract{
|
||||
mgmt,
|
||||
s,
|
||||
|
|
@ -633,5 +657,6 @@ func NewDefaultContracts(cfg config.ProtocolConfiguration) []interop.Contract {
|
|||
sese,
|
||||
tribute,
|
||||
opus,
|
||||
palam,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,4 +53,6 @@ var (
|
|||
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}
|
||||
// Palam is a hash of native Palam contract.
|
||||
Palam = util.Uint160{0x3, 0x23, 0x73, 0xfa, 0x71, 0x3a, 0x34, 0xab, 0x8d, 0x8c, 0xfa, 0xe2, 0xb0, 0x46, 0xdf, 0x53, 0x88, 0x79, 0x16, 0xae}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -51,4 +51,6 @@ const (
|
|||
Tribute int32 = -21
|
||||
// Opus is an ID of native Opus contract.
|
||||
Opus int32 = -22
|
||||
// Palam is an ID of native Palam contract.
|
||||
Palam int32 = -23
|
||||
)
|
||||
|
|
|
|||
|
|
@ -22,8 +22,9 @@ const (
|
|||
Scire = "Scire"
|
||||
Salus = "Salus"
|
||||
Sese = "Sese"
|
||||
Tribute = "Tribute"
|
||||
Opus = "Opus"
|
||||
Tribute = "Tribute"
|
||||
Opus = "Opus"
|
||||
Palam = "Palam"
|
||||
)
|
||||
|
||||
// All contains the list of all native contract names ordered by the contract ID.
|
||||
|
|
@ -50,6 +51,7 @@ var All = []string{
|
|||
Sese,
|
||||
Tribute,
|
||||
Opus,
|
||||
Palam,
|
||||
}
|
||||
|
||||
// IsValid checks if the name is a valid native contract's name.
|
||||
|
|
@ -75,5 +77,6 @@ func IsValid(name string) bool {
|
|||
name == Salus ||
|
||||
name == Sese ||
|
||||
name == Tribute ||
|
||||
name == Opus
|
||||
name == Opus ||
|
||||
name == Palam
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,713 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/tutus-one/tutus-chain/pkg/util"
|
||||
"github.com/tutus-one/tutus-chain/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
var errPalamInvalidStackItem = errors.New("invalid stack item")
|
||||
|
||||
// FlowStatus represents the status of a transaction flow.
|
||||
type FlowStatus uint8
|
||||
|
||||
const (
|
||||
FlowStatusActive FlowStatus = 0
|
||||
FlowStatusArchived FlowStatus = 1
|
||||
FlowStatusDisputed FlowStatus = 2
|
||||
)
|
||||
|
||||
// DeclassifyStatus represents the status of a declassification request.
|
||||
type DeclassifyStatus uint8
|
||||
|
||||
const (
|
||||
DeclassifyPending DeclassifyStatus = 0
|
||||
DeclassifyApproved DeclassifyStatus = 1
|
||||
DeclassifyDenied DeclassifyStatus = 2
|
||||
DeclassifyExpired DeclassifyStatus = 3
|
||||
)
|
||||
|
||||
// PalamRole represents roles for transparency access.
|
||||
type PalamRole uint8
|
||||
|
||||
const (
|
||||
PalamRoleConsumer PalamRole = 0
|
||||
PalamRoleMerchant PalamRole = 1
|
||||
PalamRoleDistributor PalamRole = 2
|
||||
PalamRoleProducer PalamRole = 3
|
||||
PalamRoleNGO PalamRole = 4
|
||||
PalamRoleAuditor PalamRole = 5
|
||||
)
|
||||
|
||||
// AccessType represents types of data access.
|
||||
type AccessType uint8
|
||||
|
||||
const (
|
||||
AccessTypeView AccessType = 0
|
||||
AccessTypeDeclassify AccessType = 1
|
||||
AccessTypeAttach AccessType = 2
|
||||
)
|
||||
|
||||
// Flow represents a transaction record with encrypted role-based payloads.
|
||||
type Flow struct {
|
||||
FlowID util.Uint256 // Unique identifier (hash of contents)
|
||||
Bucket string // Time bucket (e.g., "2025-01-15T14:00:00Z")
|
||||
Tag string // Category: COFFEE, DONATION, SUPPLY, etc.
|
||||
Amount uint64 // Value in smallest unit
|
||||
Timestamp uint32 // Block height when recorded
|
||||
Creator util.Uint160 // Who created the flow
|
||||
|
||||
// Encrypted payloads - each role has its own encrypted view
|
||||
ConsumerData []byte // Encrypted with Consumer key
|
||||
MerchantData []byte // Encrypted with Merchant key
|
||||
DistributorData []byte // Encrypted with Distributor key
|
||||
ProducerData []byte // Encrypted with Producer key
|
||||
NGOData []byte // Encrypted with NGO key
|
||||
AuditorData []byte // Encrypted with Auditor key (requires declassify)
|
||||
|
||||
// Participants (script hashes)
|
||||
Participants []util.Uint160
|
||||
|
||||
// Chain of custody
|
||||
PreviousFlowID util.Uint256 // Links flows in a supply chain
|
||||
|
||||
Status FlowStatus
|
||||
}
|
||||
|
||||
// ToStackItem converts Flow to a stack item.
|
||||
func (f *Flow) ToStackItem() stackitem.Item {
|
||||
participants := make([]stackitem.Item, len(f.Participants))
|
||||
for i, p := range f.Participants {
|
||||
participants[i] = stackitem.NewByteArray(p.BytesBE())
|
||||
}
|
||||
|
||||
return stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(f.FlowID.BytesBE()),
|
||||
stackitem.NewByteArray([]byte(f.Bucket)),
|
||||
stackitem.NewByteArray([]byte(f.Tag)),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(f.Amount))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(f.Timestamp))),
|
||||
stackitem.NewByteArray(f.Creator.BytesBE()),
|
||||
stackitem.NewByteArray(f.ConsumerData),
|
||||
stackitem.NewByteArray(f.MerchantData),
|
||||
stackitem.NewByteArray(f.DistributorData),
|
||||
stackitem.NewByteArray(f.ProducerData),
|
||||
stackitem.NewByteArray(f.NGOData),
|
||||
stackitem.NewByteArray(f.AuditorData),
|
||||
stackitem.NewArray(participants),
|
||||
stackitem.NewByteArray(f.PreviousFlowID.BytesBE()),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(f.Status))),
|
||||
})
|
||||
}
|
||||
|
||||
// FromStackItem populates Flow from a stack item.
|
||||
func (f *Flow) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok || len(arr) < 15 {
|
||||
return errPalamInvalidStackItem
|
||||
}
|
||||
|
||||
flowIDBytes, err := arr[0].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.FlowID, err = util.Uint256DecodeBytesBE(flowIDBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bucketBytes, err := arr[1].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Bucket = string(bucketBytes)
|
||||
|
||||
tagBytes, err := arr[2].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Tag = string(tagBytes)
|
||||
|
||||
amount, err := arr[3].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Amount = amount.Uint64()
|
||||
|
||||
timestamp, err := arr[4].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Timestamp = uint32(timestamp.Uint64())
|
||||
|
||||
creatorBytes, err := arr[5].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Creator, err = util.Uint160DecodeBytesBE(creatorBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.ConsumerData, err = arr[6].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.MerchantData, err = arr[7].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.DistributorData, err = arr[8].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.ProducerData, err = arr[9].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.NGOData, err = arr[10].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.AuditorData, err = arr[11].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
participantsArr, ok := arr[12].Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return errPalamInvalidStackItem
|
||||
}
|
||||
f.Participants = make([]util.Uint160, len(participantsArr))
|
||||
for i, p := range participantsArr {
|
||||
pBytes, err := p.TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Participants[i], err = util.Uint160DecodeBytesBE(pBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
prevFlowBytes, err := arr[13].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(prevFlowBytes) > 0 {
|
||||
f.PreviousFlowID, err = util.Uint256DecodeBytesBE(prevFlowBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
status, err := arr[14].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Status = FlowStatus(status.Uint64())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeclassifyRequest represents a request for elevated access to flow data.
|
||||
type DeclassifyRequest struct {
|
||||
RequestID uint64 // Unique identifier
|
||||
FlowID util.Uint256 // Target flow
|
||||
CaseID string // Legal case reference
|
||||
Reason string // Justification for access
|
||||
Requester util.Uint160 // Script hash of requester
|
||||
RequesterRole PalamRole // Must be Auditor
|
||||
|
||||
// Approval tracking
|
||||
RequiredApprovals uint32 // e.g., 2 of 3
|
||||
Approvals []util.Uint160 // Script hashes of approvers
|
||||
ApprovalTimes []uint32 // Block heights of approvals
|
||||
|
||||
// Status
|
||||
Status DeclassifyStatus
|
||||
CreatedAt uint32 // Block height when created
|
||||
ExpiresAt uint32 // Request expires if not approved
|
||||
GrantedAt uint32 // When access was granted
|
||||
}
|
||||
|
||||
// ToStackItem converts DeclassifyRequest to a stack item.
|
||||
func (d *DeclassifyRequest) ToStackItem() stackitem.Item {
|
||||
approvals := make([]stackitem.Item, len(d.Approvals))
|
||||
for i, a := range d.Approvals {
|
||||
approvals[i] = stackitem.NewByteArray(a.BytesBE())
|
||||
}
|
||||
|
||||
approvalTimes := make([]stackitem.Item, len(d.ApprovalTimes))
|
||||
for i, t := range d.ApprovalTimes {
|
||||
approvalTimes[i] = stackitem.NewBigInteger(big.NewInt(int64(t)))
|
||||
}
|
||||
|
||||
return stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewBigInteger(big.NewInt(int64(d.RequestID))),
|
||||
stackitem.NewByteArray(d.FlowID.BytesBE()),
|
||||
stackitem.NewByteArray([]byte(d.CaseID)),
|
||||
stackitem.NewByteArray([]byte(d.Reason)),
|
||||
stackitem.NewByteArray(d.Requester.BytesBE()),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(d.RequesterRole))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(d.RequiredApprovals))),
|
||||
stackitem.NewArray(approvals),
|
||||
stackitem.NewArray(approvalTimes),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(d.Status))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(d.CreatedAt))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(d.ExpiresAt))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(d.GrantedAt))),
|
||||
})
|
||||
}
|
||||
|
||||
// FromStackItem populates DeclassifyRequest from a stack item.
|
||||
func (d *DeclassifyRequest) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok || len(arr) < 13 {
|
||||
return errPalamInvalidStackItem
|
||||
}
|
||||
|
||||
requestID, err := arr[0].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.RequestID = requestID.Uint64()
|
||||
|
||||
flowIDBytes, err := arr[1].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.FlowID, err = util.Uint256DecodeBytesBE(flowIDBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
caseIDBytes, err := arr[2].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.CaseID = string(caseIDBytes)
|
||||
|
||||
reasonBytes, err := arr[3].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Reason = string(reasonBytes)
|
||||
|
||||
requesterBytes, err := arr[4].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Requester, err = util.Uint160DecodeBytesBE(requesterBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
role, err := arr[5].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.RequesterRole = PalamRole(role.Uint64())
|
||||
|
||||
required, err := arr[6].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.RequiredApprovals = uint32(required.Uint64())
|
||||
|
||||
approvalsArr, ok := arr[7].Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return errPalamInvalidStackItem
|
||||
}
|
||||
d.Approvals = make([]util.Uint160, len(approvalsArr))
|
||||
for i, a := range approvalsArr {
|
||||
aBytes, err := a.TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Approvals[i], err = util.Uint160DecodeBytesBE(aBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
timesArr, ok := arr[8].Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return errPalamInvalidStackItem
|
||||
}
|
||||
d.ApprovalTimes = make([]uint32, len(timesArr))
|
||||
for i, t := range timesArr {
|
||||
tInt, err := t.TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.ApprovalTimes[i] = uint32(tInt.Uint64())
|
||||
}
|
||||
|
||||
status, err := arr[9].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Status = DeclassifyStatus(status.Uint64())
|
||||
|
||||
createdAt, err := arr[10].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.CreatedAt = uint32(createdAt.Uint64())
|
||||
|
||||
expiresAt, err := arr[11].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.ExpiresAt = uint32(expiresAt.Uint64())
|
||||
|
||||
grantedAt, err := arr[12].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.GrantedAt = uint32(grantedAt.Uint64())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AccessLog represents a record of data access.
|
||||
type AccessLog struct {
|
||||
LogID uint64 // Unique identifier
|
||||
FlowID util.Uint256 // Which flow was accessed
|
||||
Accessor util.Uint160 // Who accessed
|
||||
AccessType AccessType // Type of access
|
||||
Timestamp uint32 // Block height
|
||||
Details string // Additional context
|
||||
}
|
||||
|
||||
// ToStackItem converts AccessLog to a stack item.
|
||||
func (a *AccessLog) ToStackItem() stackitem.Item {
|
||||
return stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewBigInteger(big.NewInt(int64(a.LogID))),
|
||||
stackitem.NewByteArray(a.FlowID.BytesBE()),
|
||||
stackitem.NewByteArray(a.Accessor.BytesBE()),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(a.AccessType))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(a.Timestamp))),
|
||||
stackitem.NewByteArray([]byte(a.Details)),
|
||||
})
|
||||
}
|
||||
|
||||
// FromStackItem populates AccessLog from a stack item.
|
||||
func (a *AccessLog) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok || len(arr) < 6 {
|
||||
return errPalamInvalidStackItem
|
||||
}
|
||||
|
||||
logID, err := arr[0].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.LogID = logID.Uint64()
|
||||
|
||||
flowIDBytes, err := arr[1].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.FlowID, err = util.Uint256DecodeBytesBE(flowIDBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accessorBytes, err := arr[2].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.Accessor, err = util.Uint160DecodeBytesBE(accessorBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accessType, err := arr[3].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.AccessType = AccessType(accessType.Uint64())
|
||||
|
||||
timestamp, err := arr[4].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.Timestamp = uint32(timestamp.Uint64())
|
||||
|
||||
detailsBytes, err := arr[5].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.Details = string(detailsBytes)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// FlowAttachment represents additional data attached to a flow.
|
||||
type FlowAttachment struct {
|
||||
AttachmentID uint64 // Unique identifier
|
||||
FlowID util.Uint256 // Parent flow
|
||||
AttachmentType string // Type of attachment
|
||||
EncryptedData []byte // Encrypted content
|
||||
Attacher util.Uint160 // Who attached
|
||||
AttachedAt uint32 // Block height
|
||||
}
|
||||
|
||||
// ToStackItem converts FlowAttachment to a stack item.
|
||||
func (fa *FlowAttachment) ToStackItem() stackitem.Item {
|
||||
return stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewBigInteger(big.NewInt(int64(fa.AttachmentID))),
|
||||
stackitem.NewByteArray(fa.FlowID.BytesBE()),
|
||||
stackitem.NewByteArray([]byte(fa.AttachmentType)),
|
||||
stackitem.NewByteArray(fa.EncryptedData),
|
||||
stackitem.NewByteArray(fa.Attacher.BytesBE()),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(fa.AttachedAt))),
|
||||
})
|
||||
}
|
||||
|
||||
// FromStackItem populates FlowAttachment from a stack item.
|
||||
func (fa *FlowAttachment) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok || len(arr) < 6 {
|
||||
return errPalamInvalidStackItem
|
||||
}
|
||||
|
||||
attachmentID, err := arr[0].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fa.AttachmentID = attachmentID.Uint64()
|
||||
|
||||
flowIDBytes, err := arr[1].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fa.FlowID, err = util.Uint256DecodeBytesBE(flowIDBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
typeBytes, err := arr[2].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fa.AttachmentType = string(typeBytes)
|
||||
|
||||
fa.EncryptedData, err = arr[3].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
attacherBytes, err := arr[4].TryBytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fa.Attacher, err = util.Uint160DecodeBytesBE(attacherBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
attachedAt, err := arr[5].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fa.AttachedAt = uint32(attachedAt.Uint64())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RolePermissions defines what each role can do.
|
||||
type RolePermissions struct {
|
||||
CanViewAggregate bool // See totals without identities
|
||||
CanViewIdentities bool // See participant identities
|
||||
CanViewDocuments bool // See attached documents
|
||||
CanAttachData bool // Add metadata to flows
|
||||
CanRequestDeclassify bool // Initiate declassification
|
||||
CanApproveDeclassify bool // Vote on declassification requests
|
||||
}
|
||||
|
||||
// ToStackItem converts RolePermissions to a stack item.
|
||||
func (rp *RolePermissions) ToStackItem() stackitem.Item {
|
||||
return stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewBool(rp.CanViewAggregate),
|
||||
stackitem.NewBool(rp.CanViewIdentities),
|
||||
stackitem.NewBool(rp.CanViewDocuments),
|
||||
stackitem.NewBool(rp.CanAttachData),
|
||||
stackitem.NewBool(rp.CanRequestDeclassify),
|
||||
stackitem.NewBool(rp.CanApproveDeclassify),
|
||||
})
|
||||
}
|
||||
|
||||
// FromStackItem populates RolePermissions from a stack item.
|
||||
func (rp *RolePermissions) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok || len(arr) < 6 {
|
||||
return errPalamInvalidStackItem
|
||||
}
|
||||
|
||||
viewAgg, err := arr[0].TryBool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rp.CanViewAggregate = viewAgg
|
||||
|
||||
viewId, err := arr[1].TryBool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rp.CanViewIdentities = viewId
|
||||
|
||||
viewDoc, err := arr[2].TryBool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rp.CanViewDocuments = viewDoc
|
||||
|
||||
attach, err := arr[3].TryBool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rp.CanAttachData = attach
|
||||
|
||||
reqDecl, err := arr[4].TryBool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rp.CanRequestDeclassify = reqDecl
|
||||
|
||||
appDecl, err := arr[5].TryBool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rp.CanApproveDeclassify = appDecl
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PalamConfig represents configurable parameters for TransparencyLedger.
|
||||
type PalamConfig struct {
|
||||
MinApprovals uint32 // Minimum approvals for declassification (default: 2)
|
||||
MaxApprovals uint32 // Maximum approvers allowed (default: 5)
|
||||
DefaultExpiration uint32 // Default expiration in blocks (default: 7 days worth)
|
||||
LogAllAccess bool // Whether to log all access (default: true)
|
||||
LogRetentionDays uint32 // How long to keep logs (default: 365)
|
||||
MaxFlowsPerBlock uint32 // Rate limit for flows (default: 1000)
|
||||
MaxRequestsPerDay uint32 // Rate limit for declassify requests (default: 10)
|
||||
}
|
||||
|
||||
// ToStackItem converts PalamConfig to a stack item.
|
||||
func (lc *PalamConfig) ToStackItem() stackitem.Item {
|
||||
return stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewBigInteger(big.NewInt(int64(lc.MinApprovals))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(lc.MaxApprovals))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(lc.DefaultExpiration))),
|
||||
stackitem.NewBool(lc.LogAllAccess),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(lc.LogRetentionDays))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(lc.MaxFlowsPerBlock))),
|
||||
stackitem.NewBigInteger(big.NewInt(int64(lc.MaxRequestsPerDay))),
|
||||
})
|
||||
}
|
||||
|
||||
// FromStackItem populates PalamConfig from a stack item.
|
||||
func (lc *PalamConfig) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok || len(arr) < 7 {
|
||||
return errPalamInvalidStackItem
|
||||
}
|
||||
|
||||
minApprovals, err := arr[0].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lc.MinApprovals = uint32(minApprovals.Uint64())
|
||||
|
||||
maxApprovals, err := arr[1].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lc.MaxApprovals = uint32(maxApprovals.Uint64())
|
||||
|
||||
defaultExp, err := arr[2].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lc.DefaultExpiration = uint32(defaultExp.Uint64())
|
||||
|
||||
logAll, err := arr[3].TryBool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lc.LogAllAccess = logAll
|
||||
|
||||
retention, err := arr[4].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lc.LogRetentionDays = uint32(retention.Uint64())
|
||||
|
||||
maxFlows, err := arr[5].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lc.MaxFlowsPerBlock = uint32(maxFlows.Uint64())
|
||||
|
||||
maxReqs, err := arr[6].TryInteger()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lc.MaxRequestsPerDay = uint32(maxReqs.Uint64())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultPalamConfig returns the default configuration.
|
||||
func DefaultPalamConfig() *PalamConfig {
|
||||
return &PalamConfig{
|
||||
MinApprovals: 2,
|
||||
MaxApprovals: 5,
|
||||
DefaultExpiration: 604800, // ~7 days in blocks (1 block/sec)
|
||||
LogAllAccess: true,
|
||||
LogRetentionDays: 365,
|
||||
MaxFlowsPerBlock: 1000,
|
||||
MaxRequestsPerDay: 10,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultRolePermissions returns permissions for each role.
|
||||
func DefaultRolePermissions(role PalamRole) *RolePermissions {
|
||||
switch role {
|
||||
case PalamRoleConsumer:
|
||||
return &RolePermissions{
|
||||
CanViewAggregate: true,
|
||||
CanViewIdentities: false,
|
||||
CanViewDocuments: false,
|
||||
CanAttachData: false,
|
||||
CanRequestDeclassify: false,
|
||||
CanApproveDeclassify: false,
|
||||
}
|
||||
case PalamRoleMerchant, PalamRoleDistributor, PalamRoleProducer, PalamRoleNGO:
|
||||
return &RolePermissions{
|
||||
CanViewAggregate: true,
|
||||
CanViewIdentities: true,
|
||||
CanViewDocuments: true,
|
||||
CanAttachData: true,
|
||||
CanRequestDeclassify: false,
|
||||
CanApproveDeclassify: false,
|
||||
}
|
||||
case PalamRoleAuditor:
|
||||
return &RolePermissions{
|
||||
CanViewAggregate: true,
|
||||
CanViewIdentities: false,
|
||||
CanViewDocuments: false,
|
||||
CanAttachData: false,
|
||||
CanRequestDeclassify: true,
|
||||
CanApproveDeclassify: false,
|
||||
}
|
||||
default:
|
||||
return &RolePermissions{}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue