feat(lns): scaffold CoreGO package with primitives and covenants
Lethean Name System — CoreGO native conversion of the HSD JavaScript sidechain. Includes Address, Transaction, BlockHeader, NameState, and Covenant types extracted from itns-sidechain/lib/primitives/, plus covenant type constants from rules.js, and a DNS resolution service stub. Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
commit
5a83dd4478
5 changed files with 415 additions and 0 deletions
5
go.mod
Normal file
5
go.mod
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
module dappco.re/go/lns
|
||||
|
||||
go 1.26.0
|
||||
|
||||
require dappco.re/go/core v0.8.0-alpha.1
|
||||
41
lns.go
Normal file
41
lns.go
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
// Package lns is the Lethean Name System — a CoreGO native conversion of the
|
||||
// HSD (Handshake) JavaScript sidechain. It provides name auctions, DNS
|
||||
// resolution, and covenant-based name management for .lthn domains.
|
||||
//
|
||||
// Register LNS as a Core service:
|
||||
//
|
||||
// c := core.New(core.WithService(lns.Register))
|
||||
//
|
||||
// Sub-packages (primitives, covenant, dns) provide the domain types
|
||||
// and resolution logic used by the service.
|
||||
package lns
|
||||
|
||||
import core "dappco.re/go/core"
|
||||
|
||||
// ServiceName is the registered name for the LNS service group.
|
||||
const ServiceName = "lns"
|
||||
|
||||
// Service is the LNS service that manages .lthn name resolution,
|
||||
// covenant processing, and name-chain state queries.
|
||||
//
|
||||
// c := core.New(core.WithService(lns.Register))
|
||||
// svc := c.Service("lns")
|
||||
type Service struct {
|
||||
*core.ServiceRuntime[serviceOptions]
|
||||
}
|
||||
|
||||
// serviceOptions holds configuration for the LNS service.
|
||||
type serviceOptions struct{}
|
||||
|
||||
// Register constructs an LNS Service bound to the provided Core instance.
|
||||
// Pass to core.WithService during Core construction:
|
||||
//
|
||||
// c := core.New(core.WithService(lns.Register))
|
||||
func Register(c *core.Core) core.Result {
|
||||
svc := &Service{
|
||||
ServiceRuntime: core.NewServiceRuntime(c, serviceOptions{}),
|
||||
}
|
||||
return core.Result{Value: svc, OK: true}
|
||||
}
|
||||
115
pkg/covenant/covenant.go
Normal file
115
pkg/covenant/covenant.go
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
// Package covenant defines the covenant type constants for the Lethean Name System.
|
||||
// Covenants encode name-system operations (auctions, registrations, transfers)
|
||||
// as typed payloads attached to transaction outputs.
|
||||
//
|
||||
// Check a covenant type:
|
||||
//
|
||||
// if covType == covenant.TypeRegister { /* name registration */ }
|
||||
//
|
||||
// Look up a type name:
|
||||
//
|
||||
// name := covenant.TypeName(covenant.TypeBid) // "BID"
|
||||
package covenant
|
||||
|
||||
// CovenantType represents the type of name-system operation encoded in a covenant.
|
||||
// Values mirror the HSD rules.js type enumeration.
|
||||
//
|
||||
// var ct covenant.CovenantType = covenant.TypeOpen
|
||||
type CovenantType uint8
|
||||
|
||||
const (
|
||||
// TypeNone is a plain transfer with no name-system operation.
|
||||
TypeNone CovenantType = 0
|
||||
|
||||
// TypeClaim imports an existing ICANN/Alexa name into the system.
|
||||
TypeClaim CovenantType = 1
|
||||
|
||||
// TypeOpen begins a name auction, making the name available for bidding.
|
||||
TypeOpen CovenantType = 2
|
||||
|
||||
// TypeBid places a sealed bid during the auction's bidding phase.
|
||||
TypeBid CovenantType = 3
|
||||
|
||||
// TypeReveal reveals a previously sealed bid after the bidding phase closes.
|
||||
TypeReveal CovenantType = 4
|
||||
|
||||
// TypeRedeem reclaims coins from a losing bid after the reveal phase.
|
||||
TypeRedeem CovenantType = 5
|
||||
|
||||
// TypeRegister completes name registration after winning an auction.
|
||||
TypeRegister CovenantType = 6
|
||||
|
||||
// TypeUpdate modifies the DNS resource data for a registered name.
|
||||
TypeUpdate CovenantType = 7
|
||||
|
||||
// TypeRenew extends the registration period for a name.
|
||||
TypeRenew CovenantType = 8
|
||||
|
||||
// TypeTransfer initiates a name transfer to a new address.
|
||||
TypeTransfer CovenantType = 9
|
||||
|
||||
// TypeFinalize completes a name transfer after the lock-up period.
|
||||
TypeFinalize CovenantType = 10
|
||||
|
||||
// TypeRevoke permanently burns a name, making it unspendable and
|
||||
// available for re-auction.
|
||||
TypeRevoke CovenantType = 11
|
||||
)
|
||||
|
||||
// typeNames maps covenant type values to their string representations.
|
||||
var typeNames = map[CovenantType]string{
|
||||
TypeNone: "NONE",
|
||||
TypeClaim: "CLAIM",
|
||||
TypeOpen: "OPEN",
|
||||
TypeBid: "BID",
|
||||
TypeReveal: "REVEAL",
|
||||
TypeRedeem: "REDEEM",
|
||||
TypeRegister: "REGISTER",
|
||||
TypeUpdate: "UPDATE",
|
||||
TypeRenew: "RENEW",
|
||||
TypeTransfer: "TRANSFER",
|
||||
TypeFinalize: "FINALIZE",
|
||||
TypeRevoke: "REVOKE",
|
||||
}
|
||||
|
||||
// TypeName returns the human-readable name for a covenant type.
|
||||
// Returns "UNKNOWN" for unrecognised type values.
|
||||
//
|
||||
// covenant.TypeName(covenant.TypeBid) // "BID"
|
||||
// covenant.TypeName(covenant.TypeRevoke) // "REVOKE"
|
||||
// covenant.TypeName(99) // "UNKNOWN"
|
||||
func TypeName(ct CovenantType) string {
|
||||
if name, ok := typeNames[ct]; ok {
|
||||
return name
|
||||
}
|
||||
return "UNKNOWN"
|
||||
}
|
||||
|
||||
// IsName returns true if the covenant type is a name-related operation
|
||||
// (anything from CLAIM through REVOKE, inclusive).
|
||||
//
|
||||
// covenant.TypeOpen.IsName() // true
|
||||
// covenant.TypeNone.IsName() // false
|
||||
func (ct CovenantType) IsName() bool {
|
||||
return ct >= TypeClaim && ct <= TypeRevoke
|
||||
}
|
||||
|
||||
// IsKnown returns true if the covenant type is a recognised type
|
||||
// (NONE through REVOKE, inclusive).
|
||||
//
|
||||
// covenant.TypeBid.IsKnown() // true
|
||||
// covenant.CovenantType(99).IsKnown() // false
|
||||
func (ct CovenantType) IsKnown() bool {
|
||||
return ct <= TypeRevoke
|
||||
}
|
||||
|
||||
// String returns the human-readable name for a covenant type.
|
||||
// Satisfies the fmt.Stringer interface.
|
||||
//
|
||||
// ct := covenant.TypeRegister
|
||||
// println(ct.String()) // "REGISTER"
|
||||
func (ct CovenantType) String() string {
|
||||
return TypeName(ct)
|
||||
}
|
||||
48
pkg/dns/resolve.go
Normal file
48
pkg/dns/resolve.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
// Package dns provides name resolution for the Lethean Name System.
|
||||
// It resolves .lthn names to their registered DNS resource records by
|
||||
// querying the name-chain state tree.
|
||||
//
|
||||
// Create a resolver and look up a name:
|
||||
//
|
||||
// svc := dns.NewService()
|
||||
// // svc.Resolve("example") — implementation pending
|
||||
package dns
|
||||
|
||||
import core "dappco.re/go/core"
|
||||
|
||||
// Service handles DNS resolution for .lthn names against the LNS chain state.
|
||||
// The full resolution logic (672 lines from the existing Go implementation)
|
||||
// will be merged in a subsequent pass.
|
||||
//
|
||||
// svc := dns.NewService()
|
||||
type Service struct {
|
||||
core *core.Core
|
||||
}
|
||||
|
||||
// NewService creates a new DNS resolution service.
|
||||
// The core instance is optional during scaffolding and can be nil.
|
||||
//
|
||||
// svc := dns.NewService()
|
||||
// svc := dns.NewService(dns.WithCore(c))
|
||||
func NewService(opts ...ServiceOption) *Service {
|
||||
s := &Service{}
|
||||
for _, opt := range opts {
|
||||
opt(s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// ServiceOption configures a DNS Service during construction.
|
||||
type ServiceOption func(*Service)
|
||||
|
||||
// WithCore sets the Core instance for the DNS service, enabling
|
||||
// access to the service registry, logging, and configuration.
|
||||
//
|
||||
// svc := dns.NewService(dns.WithCore(c))
|
||||
func WithCore(c *core.Core) ServiceOption {
|
||||
return func(s *Service) {
|
||||
s.core = c
|
||||
}
|
||||
}
|
||||
206
pkg/primitives/types.go
Normal file
206
pkg/primitives/types.go
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
// Package primitives provides the core data types for the Lethean Name System.
|
||||
// These types mirror the HSD (Handshake) sidechain primitives, converted from
|
||||
// the JavaScript reference implementation at itns-sidechain/lib/primitives/.
|
||||
//
|
||||
// Create an address from a public key hash:
|
||||
//
|
||||
// addr := primitives.Address{Version: 0, Hash: pubkeyHash}
|
||||
//
|
||||
// Build a transaction with inputs and outputs:
|
||||
//
|
||||
// tx := primitives.Transaction{Version: 0, LockTime: 0}
|
||||
// tx.Inputs = append(tx.Inputs, input)
|
||||
// tx.Outputs = append(tx.Outputs, output)
|
||||
package primitives
|
||||
|
||||
// Hash is a 32-byte hash used throughout the name system for block references,
|
||||
// transaction identifiers, and name hashes.
|
||||
//
|
||||
// var h primitives.Hash // zero-value is a valid empty hash
|
||||
type Hash [32]byte
|
||||
|
||||
// Address represents a bech32-encoded witness address on the Lethean name chain.
|
||||
// Version 0 addresses use either 20-byte (pubkey hash) or 32-byte (script hash)
|
||||
// programmes. Version 31 is reserved for nulldata (unspendable) outputs.
|
||||
//
|
||||
// addr := primitives.Address{Version: 0, Hash: blake2bDigest}
|
||||
// if addr.IsPubkeyHash() { /* 20-byte witness programme */ }
|
||||
type Address struct {
|
||||
// Version is the witness programme version (0-31).
|
||||
// Version 0 = standard witness, version 31 = nulldata.
|
||||
Version uint8
|
||||
|
||||
// Hash is the witness programme hash.
|
||||
// 20 bytes for pubkey hash, 32 bytes for script hash at version 0.
|
||||
Hash []byte
|
||||
}
|
||||
|
||||
// Outpoint references a specific output from a previous transaction.
|
||||
// Used by transaction inputs to identify the coin being spent.
|
||||
//
|
||||
// ref := primitives.Outpoint{TxHash: prevTxHash, Index: 0}
|
||||
type Outpoint struct {
|
||||
// TxHash is the hash of the transaction containing the referenced output.
|
||||
TxHash Hash
|
||||
|
||||
// Index is the zero-based position of the output within that transaction.
|
||||
Index uint32
|
||||
}
|
||||
|
||||
// Input represents a transaction input that spends a previous output.
|
||||
// Each input references an outpoint and carries a witness for validation.
|
||||
//
|
||||
// in := primitives.Input{Prevout: ref, Sequence: 0xffffffff}
|
||||
type Input struct {
|
||||
// Prevout identifies the output being spent.
|
||||
Prevout Outpoint
|
||||
|
||||
// Witness contains the witness stack items (signatures, public keys).
|
||||
Witness [][]byte
|
||||
|
||||
// Sequence is the input sequence number, used for relative timelocks.
|
||||
Sequence uint32
|
||||
}
|
||||
|
||||
// Output represents a transaction output: a value sent to an address,
|
||||
// optionally carrying a covenant for name operations.
|
||||
//
|
||||
// out := primitives.Output{Value: 1000, Address: addr, Covenant: cov}
|
||||
type Output struct {
|
||||
// Value is the amount in the smallest denomination (dollarydoos).
|
||||
Value uint64
|
||||
|
||||
// Address is the destination witness address.
|
||||
Address Address
|
||||
|
||||
// Covenant carries name-system operation data (NONE for plain transfers).
|
||||
Covenant Covenant
|
||||
}
|
||||
|
||||
// Covenant attaches name-system semantics to a transaction output.
|
||||
// The type field determines the operation (OPEN, BID, REVEAL, REGISTER, etc.)
|
||||
// and the items carry operation-specific data (name hashes, heights, records).
|
||||
//
|
||||
// cov := primitives.Covenant{Type: covenant.TypeOpen, Items: [][]byte{nameHash, heightBytes, rawName}}
|
||||
type Covenant struct {
|
||||
// Type is the covenant operation type (see pkg/covenant for constants).
|
||||
Type uint8
|
||||
|
||||
// Items is the ordered list of data payloads for this covenant.
|
||||
// Contents vary by type (name hash, height, resource data, blind, etc.).
|
||||
Items [][]byte
|
||||
}
|
||||
|
||||
// Transaction is a complete name-chain transaction containing inputs that
|
||||
// spend previous outputs and outputs that create new coins or name operations.
|
||||
//
|
||||
// tx := primitives.Transaction{Version: 0, LockTime: 0}
|
||||
type Transaction struct {
|
||||
// Version is the transaction format version.
|
||||
Version uint32
|
||||
|
||||
// Inputs is the list of inputs spending previous outputs.
|
||||
Inputs []Input
|
||||
|
||||
// Outputs is the list of new outputs created by this transaction.
|
||||
Outputs []Output
|
||||
|
||||
// LockTime is the earliest time or block height at which this
|
||||
// transaction may be included in a block.
|
||||
LockTime uint32
|
||||
}
|
||||
|
||||
// BlockHeader contains the fields present in every LNS block header.
|
||||
// The header is split into a preheader (essential for SPV) and a subheader
|
||||
// (miner-mutable data), following the HSD dual-hash PoW design.
|
||||
//
|
||||
// hdr := primitives.BlockHeader{Version: 1, Time: uint64(time.Now().Unix())}
|
||||
type BlockHeader struct {
|
||||
// Version determines which consensus rules apply to this block.
|
||||
Version uint32
|
||||
|
||||
// PrevBlock is the hash of the previous block in the chain.
|
||||
PrevBlock Hash
|
||||
|
||||
// MerkleRoot is the root hash of the transaction merkle tree.
|
||||
MerkleRoot Hash
|
||||
|
||||
// WitnessRoot is the root hash of the witness merkle tree.
|
||||
WitnessRoot Hash
|
||||
|
||||
// TreeRoot is the root hash of the name/UTXO Urkel tree.
|
||||
TreeRoot Hash
|
||||
|
||||
// ReservedRoot is reserved for future use (must be zero for now).
|
||||
ReservedRoot Hash
|
||||
|
||||
// Time is the Unix epoch timestamp (seconds) when the block was created.
|
||||
Time uint64
|
||||
|
||||
// Bits encodes the target difficulty in compact form.
|
||||
Bits uint32
|
||||
|
||||
// Nonce is iterated by the miner to find a valid PoW solution.
|
||||
Nonce uint32
|
||||
|
||||
// ExtraNonce provides additional entropy for miners (24 bytes in HSD).
|
||||
ExtraNonce []byte
|
||||
|
||||
// Mask is the PoW mask used for pool block-withholding protection (32 bytes).
|
||||
Mask []byte
|
||||
}
|
||||
|
||||
// NameState tracks the current state of a registered name on the chain.
|
||||
// Names progress through auction phases (OPENING -> BIDDING -> REVEAL -> CLOSED)
|
||||
// and can be transferred, renewed, or revoked.
|
||||
//
|
||||
// ns := primitives.NameState{Name: []byte("example"), Height: 1000}
|
||||
// if ns.IsExpired() { /* name can be re-auctioned */ }
|
||||
type NameState struct {
|
||||
// Name is the raw name bytes (1-63 characters).
|
||||
Name []byte
|
||||
|
||||
// NameHash is the blake2b hash of the name used for lookups.
|
||||
NameHash Hash
|
||||
|
||||
// Height is the block height at which the current state was established.
|
||||
Height uint32
|
||||
|
||||
// Renewal is the block height of the last renewal.
|
||||
Renewal uint32
|
||||
|
||||
// Owner references the outpoint that currently owns this name.
|
||||
Owner Outpoint
|
||||
|
||||
// Value is the locked value (winning bid amount).
|
||||
Value uint64
|
||||
|
||||
// Highest is the highest bid seen during the auction.
|
||||
Highest uint64
|
||||
|
||||
// Data is the DNS resource data attached to this name.
|
||||
Data []byte
|
||||
|
||||
// Transfer is the block height at which a transfer was initiated (0 if none).
|
||||
Transfer uint32
|
||||
|
||||
// Revoked is the block height at which the name was revoked (0 if not revoked).
|
||||
Revoked uint32
|
||||
|
||||
// Claimed is the number of times this name has been claimed.
|
||||
Claimed uint32
|
||||
|
||||
// Renewals is the total number of renewals for this name.
|
||||
Renewals uint32
|
||||
|
||||
// Registered indicates whether the name has completed the REGISTER covenant.
|
||||
Registered bool
|
||||
|
||||
// Expired indicates whether the name has passed its renewal window.
|
||||
Expired bool
|
||||
|
||||
// Weak indicates a weak claim (imported from ICANN without full proof).
|
||||
Weak bool
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue