go-lns/pkg/primitives/covenant_items.go
Virgil 9ba4498039 feat(primitives): add missing covenant builders
Co-authored-by: Virgil <virgil@lethean.io>
2026-04-02 02:20:57 +00:00

357 lines
8 KiB
Go

// SPDX-License-Identifier: EUPL-1.2
package primitives
import (
"bytes"
"encoding/binary"
core "dappco.re/go/core"
)
func normaliseCovenantIndex(index, length int) (int, bool) {
if index < 0 {
index += length
}
if index < 0 || index >= length {
return 0, false
}
return index, true
}
func sizeVarint(n int) int {
switch {
case n < 0xfd:
return 1
case n <= 0xffff:
return 3
case n <= 0xffffffff:
return 5
default:
return 9
}
}
func sizeVarBytes(n int) int {
return sizeVarint(n) + n
}
// Len reports the number of covenant items.
func (c Covenant) Len() int {
return len(c.Items)
}
// Clone returns a shallow copy of the covenant.
func (c Covenant) Clone() Covenant {
return Covenant{
Type: c.Type,
Items: c.ToArray(),
}
}
// Inject copies another covenant into this one.
func (c *Covenant) Inject(other Covenant) *Covenant {
c.Type = other.Type
c.Items = other.ToArray()
return c
}
// SetNone configures the covenant as a plain transfer with no items.
func (c *Covenant) SetNone() *Covenant {
c.Type = covenantTypeNone
c.Items = nil
return c
}
// ToArray returns a shallow copy of the covenant item slice.
func (c Covenant) ToArray() [][]byte {
if len(c.Items) == 0 {
return nil
}
items := make([][]byte, len(c.Items))
copy(items, c.Items)
return items
}
// FromArray replaces the covenant items with a shallow copy of the provided slice.
func (c *Covenant) FromArray(items [][]byte) *Covenant {
if len(items) == 0 {
c.Items = nil
return c
}
c.Items = make([][]byte, len(items))
copy(c.Items, items)
return c
}
// IndexOf reports the first matching item index or -1 if the item is absent.
func (c Covenant) IndexOf(data []byte) int {
for i, item := range c.Items {
if bytes.Equal(item, data) {
return i
}
}
return -1
}
// Get returns the item at the requested index.
func (c Covenant) Get(index int) ([]byte, error) {
index, ok := normaliseCovenantIndex(index, len(c.Items))
if !ok {
return nil, core.E("primitives.Covenant.Get", "index out of range", nil)
}
return c.Items[index], nil
}
// Set replaces or appends an item at the requested index.
func (c *Covenant) Set(index int, item []byte) error {
if index < 0 {
index += len(c.Items)
}
if index < 0 || index > len(c.Items) {
return core.E("primitives.Covenant.Set", "index out of range", nil)
}
if index == len(c.Items) {
c.Items = append(c.Items, item)
return nil
}
c.Items[index] = item
return nil
}
// Push appends an item to the covenant.
func (c *Covenant) Push(item []byte) *Covenant {
c.Items = append(c.Items, item)
return c
}
// SetOpen configures the covenant as an OPEN operation.
func (c *Covenant) SetOpen(nameHash Hash, rawName []byte) *Covenant {
c.Type = covenantTypeOpen
c.Items = nil
c.PushHash(nameHash)
c.PushU32(0)
c.Push(rawName)
return c
}
// SetBid configures the covenant as a BID operation.
func (c *Covenant) SetBid(nameHash Hash, height uint32, rawName []byte, blind Hash) *Covenant {
c.Type = covenantTypeBid
c.Items = nil
c.PushHash(nameHash)
c.PushU32(height)
c.Push(rawName)
c.PushHash(blind)
return c
}
// SetReveal configures the covenant as a REVEAL operation.
func (c *Covenant) SetReveal(nameHash Hash, height uint32, nonce Hash) *Covenant {
c.Type = covenantTypeReveal
c.Items = nil
c.PushHash(nameHash)
c.PushU32(height)
c.PushHash(nonce)
return c
}
// SetRedeem configures the covenant as a REDEEM operation.
func (c *Covenant) SetRedeem(nameHash Hash, height uint32) *Covenant {
c.Type = covenantTypeRedeem
c.Items = nil
c.PushHash(nameHash)
c.PushU32(height)
return c
}
// SetClaim configures the covenant as a CLAIM operation.
func (c *Covenant) SetClaim(nameHash Hash, height uint32, rawName []byte, flags uint8, commitHash Hash, commitHeight uint32) *Covenant {
c.Type = covenantTypeClaim
c.Items = nil
c.PushHash(nameHash)
c.PushU32(height)
c.Push(rawName)
c.PushU8(flags)
c.PushHash(commitHash)
c.PushU32(commitHeight)
return c
}
// SetRegister configures the covenant as a REGISTER operation.
func (c *Covenant) SetRegister(nameHash Hash, height uint32, record []byte, blockHash Hash) *Covenant {
c.Type = covenantTypeRegister
c.Items = nil
c.PushHash(nameHash)
c.PushU32(height)
c.Push(record)
c.PushHash(blockHash)
return c
}
// SetUpdate configures the covenant as an UPDATE operation.
func (c *Covenant) SetUpdate(nameHash Hash, height uint32, resource []byte) *Covenant {
c.Type = covenantTypeUpdate
c.Items = nil
c.PushHash(nameHash)
c.PushU32(height)
c.Push(resource)
return c
}
// SetRenew configures the covenant as a RENEW operation.
func (c *Covenant) SetRenew(nameHash Hash, height uint32, blockHash Hash) *Covenant {
c.Type = covenantTypeRenew
c.Items = nil
c.PushHash(nameHash)
c.PushU32(height)
c.PushHash(blockHash)
return c
}
// SetTransfer configures the covenant as a TRANSFER operation.
func (c *Covenant) SetTransfer(nameHash Hash, height uint32, address Address) *Covenant {
c.Type = covenantTypeTransfer
c.Items = nil
c.PushHash(nameHash)
c.PushU32(height)
c.PushU8(address.Version)
c.Push(address.Hash)
return c
}
// SetFinalize configures the covenant as a FINALIZE operation.
func (c *Covenant) SetFinalize(nameHash Hash, height uint32, rawName []byte, flags uint8, claimed uint32, renewals uint32, blockHash Hash) *Covenant {
c.Type = covenantTypeFinalize
c.Items = nil
c.PushHash(nameHash)
c.PushU32(height)
c.Push(rawName)
c.PushU8(flags)
c.PushU32(claimed)
c.PushU32(renewals)
c.PushHash(blockHash)
return c
}
// SetRevoke configures the covenant as a REVOKE operation.
func (c *Covenant) SetRevoke(nameHash Hash, height uint32) *Covenant {
c.Type = covenantTypeRevoke
c.Items = nil
c.PushHash(nameHash)
c.PushU32(height)
return c
}
// GetU8 returns the item at the requested index as a uint8.
func (c Covenant) GetU8(index int) (uint8, error) {
item, err := c.Get(index)
if err != nil {
return 0, err
}
if len(item) != 1 {
return 0, core.E("primitives.Covenant.GetU8", "item is not a uint8", nil)
}
return item[0], nil
}
// PushU8 appends a uint8 item.
func (c *Covenant) PushU8(num uint8) *Covenant {
c.Items = append(c.Items, []byte{num})
return c
}
// GetU32 returns the item at the requested index as a uint32.
func (c Covenant) GetU32(index int) (uint32, error) {
item, err := c.Get(index)
if err != nil {
return 0, err
}
if len(item) != 4 {
return 0, core.E("primitives.Covenant.GetU32", "item is not a uint32", nil)
}
return binary.LittleEndian.Uint32(item), nil
}
// PushU32 appends a uint32 item.
func (c *Covenant) PushU32(num uint32) *Covenant {
item := make([]byte, 4)
binary.LittleEndian.PutUint32(item, num)
c.Items = append(c.Items, item)
return c
}
// GetHash returns the item at the requested index as a 32-byte hash.
func (c Covenant) GetHash(index int) (Hash, error) {
item, err := c.Get(index)
if err != nil {
return Hash{}, err
}
if len(item) != len(Hash{}) {
return Hash{}, core.E("primitives.Covenant.GetHash", "item is not a hash", nil)
}
var hash Hash
copy(hash[:], item)
return hash, nil
}
// PushHash appends a 32-byte hash item.
func (c *Covenant) PushHash(hash Hash) *Covenant {
item := make([]byte, len(hash))
copy(item, hash[:])
c.Items = append(c.Items, item)
return c
}
// GetString returns the item at the requested index as a binary string.
func (c Covenant) GetString(index int) (string, error) {
item, err := c.Get(index)
if err != nil {
return "", err
}
if len(item) == 0 || len(item) > 63 {
return "", core.E("primitives.Covenant.GetString", "item is not a string", nil)
}
return string(item), nil
}
// PushString appends a binary string item.
func (c *Covenant) PushString(str string) *Covenant {
c.Items = append(c.Items, []byte(str))
return c
}
// GetSize returns the serialised size of all covenant items, excluding the
// type byte and item-count prefix.
func (c Covenant) GetSize() int {
size := 0
for _, item := range c.Items {
size += sizeVarBytes(len(item))
}
return size
}
// GetVarSize returns the serialised covenant size including the type byte and
// item-count prefix.
func (c Covenant) GetVarSize() int {
return 1 + sizeVarint(len(c.Items)) + c.GetSize()
}