go-lns/lns_test.go

1860 lines
49 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-License-Identifier: EUPL-1.2
package lns
import (
"crypto/sha3"
"encoding/binary"
"strings"
"testing"
core "dappco.re/go/core"
"dappco.re/go/lns/pkg/covenant"
"dappco.re/go/lns/pkg/primitives"
"golang.org/x/crypto/blake2b"
)
func TestServiceLifecycleHooks(t *testing.T) {
svc := &Service{}
if got := svc.OnStartup(nil); !got.OK {
t.Fatalf("OnStartup returned %#v, want OK", got)
}
if got := svc.OnShutdown(nil); !got.OK {
t.Fatalf("OnShutdown returned %#v, want OK", got)
}
}
func TestServiceHandleIPCEvents(t *testing.T) {
svc := &Service{}
if got := svc.HandleIPCEvents(nil, nil); !got.OK {
t.Fatalf("HandleIPCEvents returned %#v, want OK", got)
}
}
func TestServiceResolve(t *testing.T) {
svc := &Service{}
got, err := svc.Resolve("Foo-Bar.lthn")
if err != nil {
t.Fatalf("Resolve returned error: %v", err)
}
want := sha3.Sum256([]byte("foo-bar"))
if got != want {
t.Fatalf("Resolve returned %x, want %x", got, want)
}
got, err = svc.Resolve([]byte("Foo-Bar.lthn"))
if err != nil {
t.Fatalf("Resolve([]byte) returned error: %v", err)
}
if got != want {
t.Fatalf("Resolve([]byte) returned %x, want %x", got, want)
}
got, err = svc.GetResolve("Foo-Bar.lthn")
if err != nil {
t.Fatalf("GetResolve returned error: %v", err)
}
if got != want {
t.Fatalf("GetResolve returned %x, want %x", got, want)
}
}
func TestServiceResolveStringAndBinary(t *testing.T) {
svc := &Service{}
got, err := svc.ResolveString("Foo-Bar.lthn")
if err != nil {
t.Fatalf("ResolveString returned error: %v", err)
}
want := primitives.Hash(sha3.Sum256([]byte("foo-bar")))
if got != want {
t.Fatalf("ResolveString returned %x, want %x", got, want)
}
got, err = svc.ResolveBinary([]byte("Foo-Bar.lthn"))
if err != nil {
t.Fatalf("ResolveBinary returned error: %v", err)
}
if got != want {
t.Fatalf("ResolveBinary returned %x, want %x", got, want)
}
}
func TestServiceGetResolverAliases(t *testing.T) {
svc := &Service{}
want := primitives.Hash(sha3.Sum256([]byte("foo-bar")))
resolveCases := []struct {
name string
fn func(any) (primitives.Hash, error)
}{
{name: "GetResolveString", fn: func(name any) (primitives.Hash, error) { return svc.GetResolveString(name.(string)) }},
{name: "GetResolveBinary", fn: func(name any) (primitives.Hash, error) { return svc.GetResolveBinary(name.([]byte)) }},
{name: "GetResolveName", fn: svc.GetResolveName},
{name: "GetResolveByName", fn: svc.GetResolveByName},
{name: "GetResolveByString", fn: func(name any) (primitives.Hash, error) { return svc.GetResolveByString(name.(string)) }},
{name: "GetResolveByBinary", fn: func(name any) (primitives.Hash, error) { return svc.GetResolveByBinary(name.([]byte)) }},
{name: "GetHashString", fn: func(name any) (primitives.Hash, error) { return svc.GetHashString(name.(string)) }},
{name: "GetHashBinary", fn: func(name any) (primitives.Hash, error) { return svc.GetHashBinary(name.([]byte)) }},
{name: "GetHashName", fn: svc.GetHashName},
{name: "GetHashByName", fn: svc.GetHashByName},
{name: "GetHashByString", fn: func(name any) (primitives.Hash, error) { return svc.GetHashByString(name.(string)) }},
{name: "GetHashByBinary", fn: func(name any) (primitives.Hash, error) { return svc.GetHashByBinary(name.([]byte)) }},
}
for _, tc := range resolveCases {
var input any = "Foo-Bar.lthn"
switch tc.name {
case "GetResolveBinary", "GetResolveByBinary", "GetHashBinary", "GetHashByBinary":
input = []byte("Foo-Bar.lthn")
}
got, err := tc.fn(input)
if err != nil {
t.Fatalf("%s returned error: %v", tc.name, err)
}
if got != want {
t.Fatalf("%s returned %x, want %x", tc.name, got, want)
}
}
}
func TestServiceResolveRejectsInvalidNames(t *testing.T) {
svc := &Service{}
cases := []string{
"",
" foo-bar.lthn",
"foo-bar.lthn ",
"foo.bar.lthn",
"foo..lthn",
"foo.lthn..",
"foo-",
"test.lthn",
"foo.lthn",
}
for _, name := range cases {
if _, err := svc.Resolve(name); err == nil {
t.Fatalf("Resolve(%q) should reject the name", name)
}
}
if _, err := svc.Resolve(123); err == nil || !strings.Contains(err.Error(), "invalid name type") {
t.Fatalf("Resolve should reject unsupported input types with an invalid name type error, got %v", err)
}
}
func TestHashOperationLabels(t *testing.T) {
if _, err := Hash(123); err == nil {
t.Fatal("Hash should reject unsupported input types")
} else if got := core.Operation(err); got != "lns.Hash" {
t.Fatalf("Hash error operation = %q, want %q", got, "lns.Hash")
}
if _, err := HashString("foo-"); err == nil {
t.Fatal("HashString should reject malformed names")
} else if got := core.Operation(err); got != "lns.HashString" {
t.Fatalf("HashString error operation = %q, want %q", got, "lns.HashString")
}
if _, err := HashBinary([]byte("foo-")); err == nil {
t.Fatal("HashBinary should reject malformed names")
} else if got := core.Operation(err); got != "lns.HashBinary" {
t.Fatalf("HashBinary error operation = %q, want %q", got, "lns.HashBinary")
}
svc := &Service{}
if _, err := svc.Hash(123); err == nil {
t.Fatal("Service.Hash should reject unsupported input types")
} else if got := core.Operation(err); got != "lns.Service.Hash" {
t.Fatalf("Service.Hash error operation = %q, want %q", got, "lns.Service.Hash")
}
if _, err := svc.HashString("foo-"); err == nil {
t.Fatal("Service.HashString should reject malformed names")
} else if got := core.Operation(err); got != "lns.Service.HashString" {
t.Fatalf("Service.HashString error operation = %q, want %q", got, "lns.Service.HashString")
}
if _, err := svc.HashBinary([]byte("foo-")); err == nil {
t.Fatal("Service.HashBinary should reject malformed names")
} else if got := core.Operation(err); got != "lns.Service.HashBinary" {
t.Fatalf("Service.HashBinary error operation = %q, want %q", got, "lns.Service.HashBinary")
}
}
func TestServiceVerify(t *testing.T) {
svc := &Service{}
cases := []struct {
name any
ok bool
}{
{name: "Foo-Bar.lthn", ok: true},
{name: []byte("Foo-Bar.lthn"), ok: true},
{name: "foo.bar.lthn", ok: false},
{name: "foo-", ok: false},
{name: "foo.lthn", ok: false},
{name: 123, ok: false},
}
for _, tc := range cases {
if got := svc.Verify(tc.name); got != tc.ok {
t.Fatalf("Verify(%v) = %v, want %v", tc.name, got, tc.ok)
}
}
}
func TestServiceVerifyStringAndBinary(t *testing.T) {
svc := &Service{}
if !svc.VerifyString("Foo-Bar.lthn") {
t.Fatal("VerifyString should accept canonical names")
}
if svc.VerifyString("foo.bar.lthn") {
t.Fatal("VerifyString should reject malformed names")
}
if !svc.VerifyBinary([]byte("Foo-Bar.lthn")) {
t.Fatal("VerifyBinary should accept canonical names")
}
if svc.VerifyBinary([]byte("foo.bar.lthn")) {
t.Fatal("VerifyBinary should reject malformed names")
}
if svc.VerifyString("foo.lthn") {
t.Fatal("VerifyString should reject non-ASCII names")
}
if svc.VerifyBinary([]byte("foo.lthn")) {
t.Fatal("VerifyBinary should reject non-ASCII names")
}
}
func TestServiceGetVerifyAliases(t *testing.T) {
svc := &Service{}
verifyCases := []struct {
name string
input any
fn func(any) bool
}{
{name: "GetVerifyName", input: "Foo-Bar.lthn", fn: svc.GetVerifyName},
{name: "GetVerifyByName", input: "Foo-Bar.lthn", fn: svc.GetVerifyByName},
{name: "GetVerifyString", input: "Foo-Bar.lthn", fn: func(name any) bool { return svc.GetVerifyString(name.(string)) }},
{name: "GetVerifyBinary", input: []byte("Foo-Bar.lthn"), fn: func(name any) bool { return svc.GetVerifyBinary(name.([]byte)) }},
{name: "GetVerifyByString", input: "Foo-Bar.lthn", fn: func(name any) bool { return svc.GetVerifyByString(name.(string)) }},
{name: "GetVerifyByBinary", input: []byte("Foo-Bar.lthn"), fn: func(name any) bool { return svc.GetVerifyByBinary(name.([]byte)) }},
}
for _, tc := range verifyCases {
if !tc.fn(tc.input) {
t.Fatalf("%s should accept canonical names", tc.name)
}
}
}
func TestServiceResolveNameAliases(t *testing.T) {
svc := &Service{}
got, err := svc.ResolveName("Foo-Bar.lthn")
if err != nil {
t.Fatalf("ResolveName returned error: %v", err)
}
want := primitives.Hash(sha3.Sum256([]byte("foo-bar")))
if got != want {
t.Fatalf("ResolveName returned %x, want %x", got, want)
}
if _, err := svc.ResolveName(123); err == nil {
t.Fatal("ResolveName should reject unsupported input types")
}
}
func TestServiceHashAliases(t *testing.T) {
svc := &Service{}
got, err := svc.Hash("Foo-Bar.lthn")
if err != nil {
t.Fatalf("Hash returned error: %v", err)
}
want := primitives.Hash(sha3.Sum256([]byte("foo-bar")))
if got != want {
t.Fatalf("Hash returned %x, want %x", got, want)
}
got, err = svc.HashString("Foo-Bar.lthn")
if err != nil {
t.Fatalf("HashString returned error: %v", err)
}
if got != want {
t.Fatalf("HashString returned %x, want %x", got, want)
}
got, err = svc.HashBinary([]byte("Foo-Bar.lthn"))
if err != nil {
t.Fatalf("HashBinary returned error: %v", err)
}
if got != want {
t.Fatalf("HashBinary returned %x, want %x", got, want)
}
got, err = svc.HashName("Foo-Bar.lthn")
if err != nil {
t.Fatalf("HashName returned error: %v", err)
}
if got != want {
t.Fatalf("HashName returned %x, want %x", got, want)
}
got, err = svc.GetHash("Foo-Bar.lthn")
if err != nil {
t.Fatalf("GetHash returned error: %v", err)
}
if got != want {
t.Fatalf("GetHash returned %x, want %x", got, want)
}
got, err = svc.HashByName([]byte("Foo-Bar.lthn"))
if err != nil {
t.Fatalf("HashByName returned error: %v", err)
}
if got != want {
t.Fatalf("HashByName returned %x, want %x", got, want)
}
if _, err := svc.Hash(123); err == nil || !strings.Contains(err.Error(), "invalid name type") {
t.Fatalf("Hash should reject unsupported input types with an invalid name type error, got %v", err)
}
}
func TestServiceGetHashAndVerifyAliases(t *testing.T) {
svc := &Service{}
want := primitives.Hash(sha3.Sum256([]byte("foo-bar")))
got, err := svc.GetHash("Foo-Bar.lthn")
if err != nil {
t.Fatalf("GetHash returned error: %v", err)
}
if got != want {
t.Fatalf("GetHash returned %x, want %x", got, want)
}
if !svc.GetVerify("Foo-Bar.lthn") {
t.Fatal("GetVerify should accept canonical names")
}
if svc.GetVerify("foo.bar.lthn") {
t.Fatal("GetVerify should reject malformed names")
}
if svc.GetVerify(123) {
t.Fatal("GetVerify should reject unsupported input types")
}
}
func TestServiceRuleTables(t *testing.T) {
svc := &Service{}
if len(svc.Types()) == 0 || len(svc.TypesByVal()) == 0 {
t.Fatal("service rule tables should not be empty")
}
if len(svc.GetTypes()) != len(svc.Types()) {
t.Fatal("GetTypes should alias Types")
}
if len(svc.GetTypesByVal()) != len(svc.TypesByVal()) {
t.Fatal("GetTypesByVal should alias TypesByVal")
}
if _, ok := svc.Types()["BID"]; !ok {
t.Fatal("Types should expose BID")
}
if got, ok := svc.TypesByVal()[covenant.TypeBid]; !ok || got != "BID" {
t.Fatalf("TypesByVal[TypeBid] = %q, want %q", got, "BID")
}
if len(svc.Blacklist()) == 0 {
t.Fatal("Blacklist should not be empty")
}
if len(svc.GetBlacklist()) != len(svc.Blacklist()) {
t.Fatal("GetBlacklist should alias Blacklist")
}
if _, ok := svc.Blacklist()["test"]; !ok {
t.Fatal("Blacklist should expose test")
}
if svc.DefaultReservedCatalog() != svc.ReservedCatalog() {
t.Fatal("DefaultReservedCatalog should alias ReservedCatalog")
}
if svc.GetDefaultReservedCatalog() != svc.ReservedCatalog() {
t.Fatal("GetDefaultReservedCatalog should alias ReservedCatalog")
}
if svc.DefaultLockedCatalog() != svc.LockedCatalog() {
t.Fatal("DefaultLockedCatalog should alias LockedCatalog")
}
if svc.GetDefaultLockedCatalog() != svc.LockedCatalog() {
t.Fatal("GetDefaultLockedCatalog should alias LockedCatalog")
}
}
func TestServiceVerificationFlagTables(t *testing.T) {
svc := &Service{}
if len(svc.VerificationFlags()) != 3 {
t.Fatalf("VerificationFlags has %d entries, want 3", len(svc.VerificationFlags()))
}
if len(svc.GetVerificationFlags()) != len(svc.VerificationFlags()) {
t.Fatal("GetVerificationFlags should alias VerificationFlags")
}
if len(svc.VerificationFlagsByVal()) != len(svc.VerificationFlags()) {
t.Fatalf("VerificationFlagsByVal has %d entries, want %d", len(svc.VerificationFlagsByVal()), len(svc.VerificationFlags()))
}
if len(svc.GetVerificationFlagsByVal()) != len(svc.VerificationFlagsByVal()) {
t.Fatal("GetVerificationFlagsByVal should alias VerificationFlagsByVal")
}
if got, ok := svc.VerificationFlags()["VERIFY_COVENANTS_HARDENED"]; !ok || got != covenant.VerifyCovenantsHardened {
t.Fatalf("VerificationFlags[HARDENED] = %d, want %d", got, covenant.VerifyCovenantsHardened)
}
if got, ok := svc.VerificationFlagsByVal()[covenant.VerifyCovenantsLockup]; !ok || got != "VERIFY_COVENANTS_LOCKUP" {
t.Fatalf("VerificationFlagsByVal[LOCKUP] = %q, want %q", got, "VERIFY_COVENANTS_LOCKUP")
}
}
func TestServiceConstantGetters(t *testing.T) {
svc := &Service{}
if svc.MaxNameSize() != MaxNameSize || svc.GetMaxNameSize() != MaxNameSize {
t.Fatalf("MaxNameSize getters = %d/%d, want %d", svc.MaxNameSize(), svc.GetMaxNameSize(), MaxNameSize)
}
if svc.MaxResourceSize() != MaxResourceSize || svc.GetMaxResourceSize() != MaxResourceSize {
t.Fatalf("MaxResourceSize getters = %d/%d, want %d", svc.MaxResourceSize(), svc.GetMaxResourceSize(), MaxResourceSize)
}
if svc.VerifyCovenantsNone() != VerifyCovenantsNone || svc.GetVerifyCovenantsNone() != VerifyCovenantsNone {
t.Fatalf("VerifyCovenantsNone getters = %d/%d, want %d", svc.VerifyCovenantsNone(), svc.GetVerifyCovenantsNone(), VerifyCovenantsNone)
}
if svc.VerifyCovenantsHardened() != VerifyCovenantsHardened || svc.GetVerifyCovenantsHardened() != VerifyCovenantsHardened {
t.Fatalf("VerifyCovenantsHardened getters = %d/%d, want %d", svc.VerifyCovenantsHardened(), svc.GetVerifyCovenantsHardened(), VerifyCovenantsHardened)
}
if svc.VerifyCovenantsLockup() != VerifyCovenantsLockup || svc.GetVerifyCovenantsLockup() != VerifyCovenantsLockup {
t.Fatalf("VerifyCovenantsLockup getters = %d/%d, want %d", svc.VerifyCovenantsLockup(), svc.GetVerifyCovenantsLockup(), VerifyCovenantsLockup)
}
if svc.MandatoryVerifyCovenantFlags() != MandatoryVerifyCovenantFlags || svc.GetMandatoryVerifyCovenantFlags() != MandatoryVerifyCovenantFlags {
t.Fatalf("MandatoryVerifyCovenantFlags getters = %d/%d, want %d", svc.MandatoryVerifyCovenantFlags(), svc.GetMandatoryVerifyCovenantFlags(), MandatoryVerifyCovenantFlags)
}
if svc.MaxCovenantSize() != MaxCovenantSize || svc.GetMaxCovenantSize() != MaxCovenantSize {
t.Fatalf("MaxCovenantSize getters = %d/%d, want %d", svc.MaxCovenantSize(), svc.GetMaxCovenantSize(), MaxCovenantSize)
}
if svc.CovenantMaxSize() != CovenantMaxSize || svc.GetCovenantMaxSize() != CovenantMaxSize {
t.Fatalf("CovenantMaxSize getters = %d/%d, want %d", svc.CovenantMaxSize(), svc.GetCovenantMaxSize(), CovenantMaxSize)
}
}
func TestServiceHashByStringAndBinaryAliases(t *testing.T) {
svc := &Service{}
want := primitives.Hash(sha3.Sum256([]byte("foo-bar")))
got, err := svc.HashByString("Foo-Bar.lthn")
if err != nil {
t.Fatalf("HashByString returned error: %v", err)
}
if got != want {
t.Fatalf("HashByString returned %x, want %x", got, want)
}
got, err = svc.HashByBinary([]byte("Foo-Bar.lthn"))
if err != nil {
t.Fatalf("HashByBinary returned error: %v", err)
}
if got != want {
t.Fatalf("HashByBinary returned %x, want %x", got, want)
}
}
func TestServiceResolveByNameAliases(t *testing.T) {
svc := &Service{}
got, err := svc.ResolveByName("Foo-Bar.lthn")
if err != nil {
t.Fatalf("ResolveByName returned error: %v", err)
}
want := primitives.Hash(sha3.Sum256([]byte("foo-bar")))
if got != want {
t.Fatalf("ResolveByName returned %x, want %x", got, want)
}
if _, err := svc.ResolveByName(123); err == nil {
t.Fatal("ResolveByName should reject unsupported input types")
}
}
func TestServiceVerifyNameAliases(t *testing.T) {
svc := &Service{}
if !svc.VerifyName("Foo-Bar.lthn") {
t.Fatal("VerifyName should accept canonical names")
}
if svc.VerifyName("foo.bar.lthn") {
t.Fatal("VerifyName should reject malformed names")
}
if svc.VerifyName(123) {
t.Fatal("VerifyName should reject unsupported input types")
}
}
func TestServiceResolveByStringAndBinaryAliases(t *testing.T) {
svc := &Service{}
want := primitives.Hash(sha3.Sum256([]byte("foo-bar")))
got, err := svc.ResolveByString("Foo-Bar.lthn")
if err != nil {
t.Fatalf("ResolveByString returned error: %v", err)
}
if got != want {
t.Fatalf("ResolveByString returned %x, want %x", got, want)
}
got, err = svc.ResolveByBinary([]byte("Foo-Bar.lthn"))
if err != nil {
t.Fatalf("ResolveByBinary returned error: %v", err)
}
if got != want {
t.Fatalf("ResolveByBinary returned %x, want %x", got, want)
}
}
func TestServiceVerifyByStringAndBinaryAliases(t *testing.T) {
svc := &Service{}
if !svc.VerifyByString("Foo-Bar.lthn") {
t.Fatal("VerifyByString should accept canonical names")
}
if svc.VerifyByString("foo.bar.lthn") {
t.Fatal("VerifyByString should reject malformed names")
}
if !svc.VerifyByBinary([]byte("Foo-Bar.lthn")) {
t.Fatal("VerifyByBinary should accept canonical names")
}
if svc.VerifyByBinary([]byte("foo.bar.lthn")) {
t.Fatal("VerifyByBinary should reject malformed names")
}
}
func TestServiceVerifyByNameAliases(t *testing.T) {
svc := &Service{}
if !svc.VerifyByName("Foo-Bar.lthn") {
t.Fatal("VerifyByName should accept canonical names")
}
if svc.VerifyByName("foo.bar.lthn") {
t.Fatal("VerifyByName should reject malformed names")
}
if svc.VerifyByName(123) {
t.Fatal("VerifyByName should reject unsupported input types")
}
}
func TestServiceBlind(t *testing.T) {
svc := &Service{}
var nonce primitives.Hash
for i := range nonce {
nonce[i] = byte(i)
}
got, err := svc.Blind(0x1122334455667788, nonce)
if err != nil {
t.Fatalf("Blind returned error: %v", err)
}
var input [40]byte
binary.LittleEndian.PutUint64(input[:8], 0x1122334455667788)
copy(input[8:], nonce[:])
want := blake2b.Sum256(input[:])
if got != want {
t.Fatalf("Blind returned %x, want %x", got, want)
}
}
func TestServiceTypeName(t *testing.T) {
svc := &Service{}
if got := svc.TypeName(covenant.TypeBid); got != "BID" {
t.Fatalf("TypeName(TypeBid) = %q, want %q", got, "BID")
}
if got := svc.TypeName(covenant.CovenantType(99)); got != "UNKNOWN" {
t.Fatalf("TypeName(99) = %q, want %q", got, "UNKNOWN")
}
}
func TestServiceCovenantTypePredicates(t *testing.T) {
svc := &Service{}
if !svc.IsName(covenant.TypeOpen) || !svc.GetIsName(covenant.TypeOpen) {
t.Fatal("IsName should report open covenants")
}
if svc.IsName(covenant.TypeNone) || svc.GetIsName(covenant.TypeNone) {
t.Fatal("IsName should reject non-name covenants")
}
if !svc.IsKnown(covenant.TypeBid) || !svc.GetIsKnown(covenant.TypeBid) {
t.Fatal("IsKnown should report recognized covenants")
}
if svc.IsKnown(covenant.CovenantType(99)) || svc.GetIsKnown(covenant.CovenantType(99)) {
t.Fatal("IsKnown should reject unknown covenants")
}
if !svc.IsLinked(covenant.TypeReveal) || !svc.GetIsLinked(covenant.TypeReveal) {
t.Fatal("IsLinked should report linked covenants")
}
if svc.IsLinked(covenant.TypeOpen) || svc.GetIsLinked(covenant.TypeOpen) {
t.Fatal("IsLinked should reject unlinked covenants")
}
}
func TestServiceRolloutHelpers(t *testing.T) {
svc := &Service{}
var hash primitives.Hash
rules := NameRules{
AuctionStart: 100,
RolloutInterval: 7,
ClaimPeriod: 100,
AlexaLockupPeriod: 250,
}
start, week := svc.GetRollout(hash, rules)
if start != 100 || week != 0 {
t.Fatalf("GetRollout(zero) = (%d, %d), want (100, 0)", start, week)
}
if !svc.HasRollout(hash, 100, rules) {
t.Fatal("HasRollout should accept the rollout start height")
}
reservedHash, err := covenant.HashString("reserved")
if err != nil {
t.Fatalf("HashString returned error: %v", err)
}
if !svc.IsReserved(reservedHash, 99, rules) {
t.Fatal("IsReserved should report reserved hashes before the claim period")
}
rootHash, err := covenant.HashString("nec")
if err != nil {
t.Fatalf("HashString returned error: %v", err)
}
if !svc.IsLockedUp(rootHash, 100, rules) {
t.Fatal("IsLockedUp should keep root hashes locked after the claim period")
}
}
func TestServiceGrindAndCountHelpers(t *testing.T) {
svc := &Service{}
tx := primitives.Transaction{
Outputs: []primitives.Output{
{Covenant: primitives.Covenant{Type: uint8(covenant.TypeOpen)}},
{Covenant: primitives.Covenant{Type: uint8(covenant.TypeClaim)}},
{Covenant: primitives.Covenant{Type: uint8(covenant.TypeUpdate)}},
{Covenant: primitives.Covenant{Type: uint8(covenant.TypeTransfer)}},
{Covenant: primitives.Covenant{Type: uint8(covenant.TypeRevoke)}},
{Covenant: primitives.Covenant{Type: uint8(covenant.TypeRegister)}},
{Covenant: primitives.Covenant{Type: uint8(covenant.TypeRenew)}},
{Covenant: primitives.Covenant{Type: uint8(covenant.TypeFinalize)}},
},
}
if got := svc.CountOpens(tx); got != 1 {
t.Fatalf("CountOpens() = %d, want 1", got)
}
if got := svc.GetCountOpens(tx); got != 1 {
t.Fatalf("GetCountOpens() = %d, want 1", got)
}
if got := svc.CountUpdates(tx); got != 5 {
t.Fatalf("CountUpdates() = %d, want 5", got)
}
if got := svc.GetCountUpdates(tx); got != 5 {
t.Fatalf("GetCountUpdates() = %d, want 5", got)
}
if got := svc.CountRenewals(tx); got != 3 {
t.Fatalf("CountRenewals() = %d, want 3", got)
}
if got := svc.GetCountRenewals(tx); got != 3 {
t.Fatalf("GetCountRenewals() = %d, want 3", got)
}
rules := NameRules{
AuctionStart: 100,
RolloutInterval: 7,
}
name, err := svc.GrindName(8, 100, rules)
if err != nil {
t.Fatalf("GrindName returned error: %v", err)
}
alias, err := svc.GetGrindName(8, 100, rules)
if err != nil {
t.Fatalf("GetGrindName returned error: %v", err)
}
if len(name) != 8 {
t.Fatalf("GrindName returned %q with length %d, want 8", name, len(name))
}
if len(alias) != 8 {
t.Fatalf("GetGrindName returned %q with length %d, want 8", alias, len(alias))
}
hash, err := covenant.HashString(name)
if err != nil {
t.Fatalf("HashString returned error: %v", err)
}
if !svc.HasRollout(hash, 100, rules) {
t.Fatalf("GrindName returned %q that does not satisfy rollout", name)
}
}
func TestServiceGetBlindAndGetTypeNameAliases(t *testing.T) {
svc := &Service{}
var nonce primitives.Hash
got, err := svc.GetBlind(1, nonce)
if err != nil {
t.Fatalf("GetBlind returned error: %v", err)
}
want, err := svc.Blind(1, nonce)
if err != nil {
t.Fatalf("Blind returned error: %v", err)
}
if got != want {
t.Fatalf("GetBlind returned %x, want %x", got, want)
}
if got := svc.GetTypeName(covenant.TypeBid); got != "BID" {
t.Fatalf("GetTypeName(TypeBid) = %q, want %q", got, "BID")
}
}
func TestServiceCoreAccessors(t *testing.T) {
runtime := core.NewServiceRuntime(nil, serviceOptions{})
svc := &Service{ServiceRuntime: runtime}
if svc.Core() != nil {
t.Fatal("Core should return nil when the service has no Core")
}
if svc.GetCore() != nil {
t.Fatal("GetCore should alias Core")
}
if got := svc.ServiceName(); got != ServiceName {
t.Fatalf("ServiceName() = %q, want %q", got, ServiceName)
}
if got := svc.GetServiceName(); got != ServiceName {
t.Fatalf("GetServiceName() = %q, want %q", got, ServiceName)
}
}
func TestServiceCoreNilSafety(t *testing.T) {
var svc *Service
if svc.Core() != nil {
t.Fatal("Core should return nil for a nil receiver")
}
if svc.GetCore() != nil {
t.Fatal("GetCore should return nil for a nil receiver")
}
if got := (&Service{}).Core(); got != nil {
t.Fatal("Core should return nil for a zero-value service")
}
}
func TestServiceNilReceiverCatalogAccessors(t *testing.T) {
var svc *Service
if svc.ReservedCatalog() != Reserved {
t.Fatal("ReservedCatalog should fall back to the package catalog on a nil receiver")
}
if svc.GetReservedCatalog() != Reserved {
t.Fatal("GetReservedCatalog should fall back to the package catalog on a nil receiver")
}
if svc.LockedCatalog() != Locked {
t.Fatal("LockedCatalog should fall back to the package catalog on a nil receiver")
}
if svc.GetLockedCatalog() != Locked {
t.Fatal("GetLockedCatalog should fall back to the package catalog on a nil receiver")
}
if svc.ReservedSize() != Reserved.Size() {
t.Fatal("ReservedSize should be nil-safe")
}
if svc.LockedSize() != Locked.Size() {
t.Fatal("LockedSize should be nil-safe")
}
if len(svc.ReservedEntries()) != len(Reserved.Entries()) {
t.Fatal("ReservedEntries should be nil-safe")
}
if len(svc.LockedEntries()) != len(Locked.Entries()) {
t.Fatal("LockedEntries should be nil-safe")
}
}
func TestNewService(t *testing.T) {
svc := NewService(nil)
if svc == nil {
t.Fatal("NewService should return a service instance")
}
if svc.Core() != nil {
t.Fatal("NewService(nil) should preserve a nil Core")
}
if got := svc.ServiceName(); got != ServiceName {
t.Fatalf("NewService ServiceName() = %q, want %q", got, ServiceName)
}
}
func TestNewServiceWithOptions(t *testing.T) {
c := core.New()
svc := NewServiceWithOptions(WithCore(c))
if svc == nil {
t.Fatal("NewServiceWithOptions should return a service instance")
}
if svc.Core() != c {
t.Fatal("WithCore should attach the provided Core instance")
}
if got := svc.ServiceName(); got != ServiceName {
t.Fatalf("NewServiceWithOptions ServiceName() = %q, want %q", got, ServiceName)
}
}
func TestNewServiceWithNilCoreOption(t *testing.T) {
svc := NewServiceWithOptions(WithCore(nil))
if svc == nil {
t.Fatal("NewServiceWithOptions should return a service instance")
}
if svc.Core() != nil {
t.Fatal("WithCore(nil) should preserve a nil Core")
}
}
func TestNewServiceWithCatalogOverrides(t *testing.T) {
reserved := covenant.DefaultReservedCatalog()
locked := covenant.DefaultLockedCatalog()
svc := NewServiceWithOptions(
WithReservedCatalog(reserved),
WithLockedCatalog(locked),
)
if svc.ReservedCatalog() != reserved {
t.Fatal("WithReservedCatalog should install the provided reserved catalog")
}
if svc.LockedCatalog() != locked {
t.Fatal("WithLockedCatalog should install the provided locked catalog")
}
}
func TestCatalogOptionIgnoresNilCatalogs(t *testing.T) {
svc := NewServiceWithOptions(
WithReservedCatalog(nil),
WithLockedCatalog(nil),
)
if svc.ReservedCatalog() != ReservedCatalog() {
t.Fatal("WithReservedCatalog(nil) should not replace the default reserved catalog")
}
if svc.LockedCatalog() != LockedCatalog() {
t.Fatal("WithLockedCatalog(nil) should not replace the default locked catalog")
}
}
func TestRegisterRejectsNilCore(t *testing.T) {
res := Register(nil)
if res.OK {
t.Fatal("Register(nil) should fail")
}
if _, ok := res.Value.(error); !ok {
t.Fatalf("Register(nil) should return an error result, got %T", res.Value)
}
}
func TestServiceGetReserved(t *testing.T) {
svc := &Service{}
item, ok := svc.GetReserved("RESERVED.lthn")
if !ok {
t.Fatal("GetReserved should find the reserved reference entry")
}
if item.Name != "reserved" {
t.Fatalf("item.Name = %q, want %q", item.Name, "reserved")
}
if item.Target != "reserved.com." {
t.Fatalf("item.Target = %q, want %q", item.Target, "reserved.com.")
}
hash, err := covenant.HashString("reserved")
if err != nil {
t.Fatalf("HashString returned error: %v", err)
}
if item.Hash != hash {
t.Fatalf("item.Hash = %x, want %x", item.Hash, hash)
}
if _, ok := svc.GetReserved([]byte("reserved.lthn")); !ok {
t.Fatal("GetReserved([]byte) should find the reserved reference entry")
}
if _, ok := svc.GetReserved(123); ok {
t.Fatal("GetReserved should reject unsupported input types")
}
}
func TestServiceHasReserved(t *testing.T) {
svc := &Service{}
if !svc.HasReserved("RESERVED.lthn") {
t.Fatal("HasReserved should report canonical reserved names")
}
if !svc.HasReserved([]byte("reserved.lthn")) {
t.Fatal("HasReserved([]byte) should report canonical reserved names")
}
if svc.HasReserved("not-reserved.lthn") {
t.Fatal("HasReserved should return false for unknown names")
}
if svc.HasReserved(123) {
t.Fatal("HasReserved should reject unsupported input types")
}
}
func TestServiceGetReservedByName(t *testing.T) {
svc := &Service{}
item, ok := svc.GetReservedByName("RESERVED")
if !ok {
t.Fatal("GetReservedByName should find the reserved reference entry")
}
if item.Name != "reserved" {
t.Fatalf("item.Name = %q, want %q", item.Name, "reserved")
}
if _, ok := svc.GetReservedByName([]byte("reserved")); !ok {
t.Fatal("GetReservedByName([]byte) should find the reserved reference entry")
}
if _, ok := svc.GetReservedByName("RESERVED.lthn"); !ok {
t.Fatal("GetReservedByName should also accept canonical reserved names")
}
if _, ok := svc.GetReservedByName(123); ok {
t.Fatal("GetReservedByName should reject unsupported input types")
}
}
func TestServiceGetReservedStringAndBinary(t *testing.T) {
svc := &Service{}
item, ok := svc.GetReservedString("RESERVED")
if !ok {
t.Fatal("GetReservedString should find the reserved catalog label")
}
if item.Name != "reserved" {
t.Fatalf("item.Name = %q, want %q", item.Name, "reserved")
}
item, ok = svc.GetReservedBinary([]byte("reserved"))
if !ok {
t.Fatal("GetReservedBinary should find the reserved catalog label")
}
if item.Name != "reserved" {
t.Fatalf("item.Name = %q, want %q", item.Name, "reserved")
}
if !svc.HasReservedString("reserved") {
t.Fatal("HasReservedString should report reserved catalog labels")
}
if !svc.HasReservedBinary([]byte("RESERVED")) {
t.Fatal("HasReservedBinary should report reserved catalog labels")
}
if _, ok := svc.GetReservedString("RESERVED.lthn"); !ok {
t.Fatal("GetReservedString should also accept canonical reserved names")
}
if _, ok := svc.GetReservedBinary([]byte("reserved.lthn")); !ok {
t.Fatal("GetReservedBinary should also accept canonical reserved names")
}
if !svc.HasReservedString("reserved.lthn") {
t.Fatal("HasReservedString should report canonical reserved names")
}
if !svc.HasReservedBinary([]byte("RESERVED.lthn")) {
t.Fatal("HasReservedBinary should report canonical reserved names")
}
}
func TestServiceGetReservedByStringAndBinary(t *testing.T) {
svc := &Service{}
item, ok := svc.GetReservedByString("RESERVED")
if !ok {
t.Fatal("GetReservedByString should find the reserved catalog label")
}
if item.Name != "reserved" {
t.Fatalf("item.Name = %q, want %q", item.Name, "reserved")
}
item, ok = svc.GetReservedByBinary([]byte("reserved"))
if !ok {
t.Fatal("GetReservedByBinary should find the reserved catalog label")
}
if item.Name != "reserved" {
t.Fatalf("item.Name = %q, want %q", item.Name, "reserved")
}
if !svc.HasReservedByString("reserved") {
t.Fatal("HasReservedByString should report reserved catalog labels")
}
if !svc.HasReservedByBinary([]byte("RESERVED")) {
t.Fatal("HasReservedByBinary should report reserved catalog labels")
}
}
func TestServiceHasReservedByName(t *testing.T) {
svc := &Service{}
if !svc.HasReservedByName("RESERVED") {
t.Fatal("HasReservedByName should report reserved catalog labels")
}
if !svc.HasReservedByName([]byte("reserved")) {
t.Fatal("HasReservedByName([]byte) should report reserved catalog labels")
}
if !svc.HasReservedByName("reserved.lthn") {
t.Fatal("HasReservedByName should report canonical reserved names")
}
if svc.HasReservedByName("not-reserved") {
t.Fatal("HasReservedByName should return false for unknown labels")
}
if svc.HasReservedByName(123) {
t.Fatal("HasReservedByName should reject unsupported input types")
}
}
func TestServiceReservedNameAliases(t *testing.T) {
svc := &Service{}
item, ok := svc.GetReservedName("RESERVED")
if !ok {
t.Fatal("GetReservedName should find the reserved catalog label")
}
if item.Name != "reserved" {
t.Fatalf("item.Name = %q, want %q", item.Name, "reserved")
}
item, ok = svc.GetReservedName("RESERVED.lthn")
if !ok {
t.Fatal("GetReservedName should also accept canonical reserved names")
}
if item.Name != "reserved" {
t.Fatalf("item.Name = %q, want %q", item.Name, "reserved")
}
if !svc.HasReservedName("reserved") {
t.Fatal("HasReservedName should report reserved catalog labels")
}
if !svc.HasReservedName("reserved.lthn") {
t.Fatal("HasReservedName should report canonical reserved names")
}
}
func TestServiceGetReservedHash(t *testing.T) {
svc := &Service{}
hash, err := covenant.HashString("reserved")
if err != nil {
t.Fatalf("HashString returned error: %v", err)
}
item, ok := svc.GetReservedHash(hash)
if !ok {
t.Fatal("GetReservedHash should find the reserved reference entry")
}
if item.Name != "reserved" {
t.Fatalf("item.Name = %q, want %q", item.Name, "reserved")
}
if !svc.HasReservedHash(hash) {
t.Fatal("HasReservedHash should report canonical reserved hashes")
}
if svc.HasReservedHash(primitives.Hash{}) {
t.Fatal("HasReservedHash should return false for unknown hashes")
}
}
func TestServiceGetReservedByHash(t *testing.T) {
svc := &Service{}
hash, err := covenant.HashString("reserved")
if err != nil {
t.Fatalf("HashString returned error: %v", err)
}
item, ok := svc.GetReservedByHash(hash)
if !ok {
t.Fatal("GetReservedByHash should find the reserved reference entry")
}
if item.Name != "reserved" {
t.Fatalf("item.Name = %q, want %q", item.Name, "reserved")
}
if !svc.HasReservedByHash(hash) {
t.Fatal("HasReservedByHash should report canonical reserved hashes")
}
if svc.HasReservedByHash(primitives.Hash{}) {
t.Fatal("HasReservedByHash should return false for unknown hashes")
}
}
func TestServiceGetLocked(t *testing.T) {
svc := &Service{}
item, ok := svc.GetLocked("NEC.lthn")
if !ok {
t.Fatal("GetLocked should find the locked reference entry")
}
if item.Name != "nec" {
t.Fatalf("item.Name = %q, want %q", item.Name, "nec")
}
if item.Target != "nec." {
t.Fatalf("item.Target = %q, want %q", item.Target, "nec.")
}
if !item.Root || item.Custom {
t.Fatalf("unexpected flags on nec: %#v", item)
}
if _, ok := svc.GetLocked([]byte("nec.lthn")); !ok {
t.Fatal("GetLocked([]byte) should find the locked reference entry")
}
if _, ok := svc.GetLocked(123); ok {
t.Fatal("GetLocked should reject unsupported input types")
}
}
func TestServiceHasLocked(t *testing.T) {
svc := &Service{}
if !svc.HasLocked("NEC.lthn") {
t.Fatal("HasLocked should report canonical locked names")
}
if !svc.HasLocked([]byte("nec.lthn")) {
t.Fatal("HasLocked([]byte) should report canonical locked names")
}
if svc.HasLocked("not-locked.lthn") {
t.Fatal("HasLocked should return false for unknown names")
}
if svc.HasLocked(123) {
t.Fatal("HasLocked should reject unsupported input types")
}
}
func TestServiceGetLockedByName(t *testing.T) {
svc := &Service{}
item, ok := svc.GetLockedByName("NEC")
if !ok {
t.Fatal("GetLockedByName should find the locked reference entry")
}
if item.Name != "nec" {
t.Fatalf("item.Name = %q, want %q", item.Name, "nec")
}
if _, ok := svc.GetLockedByName([]byte("nec")); !ok {
t.Fatal("GetLockedByName([]byte) should find the locked reference entry")
}
if _, ok := svc.GetLockedByName("NEC.lthn"); !ok {
t.Fatal("GetLockedByName should also accept canonical locked names")
}
if _, ok := svc.GetLockedByName(123); ok {
t.Fatal("GetLockedByName should reject unsupported input types")
}
}
func TestServiceGetLockedStringAndBinary(t *testing.T) {
svc := &Service{}
item, ok := svc.GetLockedString("NEC")
if !ok {
t.Fatal("GetLockedString should find the locked catalog label")
}
if item.Name != "nec" {
t.Fatalf("item.Name = %q, want %q", item.Name, "nec")
}
item, ok = svc.GetLockedBinary([]byte("nec"))
if !ok {
t.Fatal("GetLockedBinary should find the locked catalog label")
}
if item.Name != "nec" {
t.Fatalf("item.Name = %q, want %q", item.Name, "nec")
}
if !svc.HasLockedString("nec") {
t.Fatal("HasLockedString should report locked catalog labels")
}
if !svc.HasLockedBinary([]byte("NEC")) {
t.Fatal("HasLockedBinary should report locked catalog labels")
}
if _, ok := svc.GetLockedString("NEC.lthn"); !ok {
t.Fatal("GetLockedString should also accept canonical locked names")
}
if _, ok := svc.GetLockedBinary([]byte("nec.lthn")); !ok {
t.Fatal("GetLockedBinary should also accept canonical locked names")
}
if !svc.HasLockedString("nec.lthn") {
t.Fatal("HasLockedString should report canonical locked names")
}
if !svc.HasLockedBinary([]byte("NEC.lthn")) {
t.Fatal("HasLockedBinary should report canonical locked names")
}
}
func TestServiceGetLockedByStringAndBinary(t *testing.T) {
svc := &Service{}
item, ok := svc.GetLockedByString("NEC")
if !ok {
t.Fatal("GetLockedByString should find the locked catalog label")
}
if item.Name != "nec" {
t.Fatalf("item.Name = %q, want %q", item.Name, "nec")
}
item, ok = svc.GetLockedByBinary([]byte("nec"))
if !ok {
t.Fatal("GetLockedByBinary should find the locked catalog label")
}
if item.Name != "nec" {
t.Fatalf("item.Name = %q, want %q", item.Name, "nec")
}
if !svc.HasLockedByString("nec") {
t.Fatal("HasLockedByString should report locked catalog labels")
}
if !svc.HasLockedByBinary([]byte("NEC")) {
t.Fatal("HasLockedByBinary should report locked catalog labels")
}
}
func TestServiceHasLockedByName(t *testing.T) {
svc := &Service{}
if !svc.HasLockedByName("NEC") {
t.Fatal("HasLockedByName should report locked catalog labels")
}
if !svc.HasLockedByName([]byte("nec")) {
t.Fatal("HasLockedByName([]byte) should report locked catalog labels")
}
if !svc.HasLockedByName("nec.lthn") {
t.Fatal("HasLockedByName should report canonical locked names")
}
if svc.HasLockedByName("not-locked") {
t.Fatal("HasLockedByName should return false for unknown labels")
}
if svc.HasLockedByName(123) {
t.Fatal("HasLockedByName should reject unsupported input types")
}
}
func TestServiceLockedNameAliases(t *testing.T) {
svc := &Service{}
item, ok := svc.GetLockedName("NEC")
if !ok {
t.Fatal("GetLockedName should find the locked catalog label")
}
if item.Name != "nec" {
t.Fatalf("item.Name = %q, want %q", item.Name, "nec")
}
item, ok = svc.GetLockedName("NEC.lthn")
if !ok {
t.Fatal("GetLockedName should also accept canonical locked names")
}
if item.Name != "nec" {
t.Fatalf("item.Name = %q, want %q", item.Name, "nec")
}
if !svc.HasLockedName("nec") {
t.Fatal("HasLockedName should report locked catalog labels")
}
if !svc.HasLockedName("nec.lthn") {
t.Fatal("HasLockedName should report canonical locked names")
}
}
func TestServiceGetLockedHash(t *testing.T) {
svc := &Service{}
hash, err := covenant.HashString("nec")
if err != nil {
t.Fatalf("HashString returned error: %v", err)
}
item, ok := svc.GetLockedHash(hash)
if !ok {
t.Fatal("GetLockedHash should find the locked reference entry")
}
if item.Name != "nec" {
t.Fatalf("item.Name = %q, want %q", item.Name, "nec")
}
if !svc.HasLockedHash(hash) {
t.Fatal("HasLockedHash should report canonical locked hashes")
}
if svc.HasLockedHash(primitives.Hash{}) {
t.Fatal("HasLockedHash should return false for unknown hashes")
}
}
func TestServiceGetLockedByHash(t *testing.T) {
svc := &Service{}
hash, err := covenant.HashString("nec")
if err != nil {
t.Fatalf("HashString returned error: %v", err)
}
item, ok := svc.GetLockedByHash(hash)
if !ok {
t.Fatal("GetLockedByHash should find the locked reference entry")
}
if item.Name != "nec" {
t.Fatalf("item.Name = %q, want %q", item.Name, "nec")
}
if !svc.HasLockedByHash(hash) {
t.Fatal("HasLockedByHash should report canonical locked hashes")
}
if svc.HasLockedByHash(primitives.Hash{}) {
t.Fatal("HasLockedByHash should return false for unknown hashes")
}
}
func TestServiceReservedCatalog(t *testing.T) {
svc := &Service{}
catalog := svc.ReservedCatalog()
getCatalog := svc.GetReservedCatalog()
defaultCatalog := DefaultReservedCatalog()
packageGetCatalog := GetReservedCatalog()
if catalog == nil {
t.Fatal("ReservedCatalog should return a catalog")
}
if getCatalog == nil {
t.Fatal("GetReservedCatalog should return a catalog")
}
if catalog != Reserved {
t.Fatal("ReservedCatalog should return the exported Reserved instance")
}
if getCatalog != catalog {
t.Fatal("GetReservedCatalog should alias ReservedCatalog")
}
if defaultCatalog != catalog {
t.Fatal("DefaultReservedCatalog should alias the covenant default catalog")
}
if packageGetCatalog != catalog {
t.Fatal("GetReservedCatalog should alias DefaultReservedCatalog")
}
if got := svc.ReservedSize(); got != catalog.Size() {
t.Fatalf("ReservedSize() = %d, want %d", got, catalog.Size())
}
if got := svc.GetReservedSize(); got != catalog.Size() {
t.Fatalf("GetReservedSize() = %d, want %d", got, catalog.Size())
}
if got := svc.ReservedNameValue(); got != catalog.NameValue() {
t.Fatalf("ReservedNameValue() = %d, want %d", got, catalog.NameValue())
}
if got := svc.GetReservedNameValue(); got != catalog.NameValue() {
t.Fatalf("GetReservedNameValue() = %d, want %d", got, catalog.NameValue())
}
if got := svc.ReservedRootValue(); got != catalog.RootValue() {
t.Fatalf("ReservedRootValue() = %d, want %d", got, catalog.RootValue())
}
if got := svc.GetReservedRootValue(); got != catalog.RootValue() {
t.Fatalf("GetReservedRootValue() = %d, want %d", got, catalog.RootValue())
}
if got := svc.ReservedTopValue(); got != catalog.TopValue() {
t.Fatalf("ReservedTopValue() = %d, want %d", got, catalog.TopValue())
}
if got := svc.GetReservedTopValue(); got != catalog.TopValue() {
t.Fatalf("GetReservedTopValue() = %d, want %d", got, catalog.TopValue())
}
if got := svc.NameValue(); got != catalog.NameValue() {
t.Fatalf("NameValue() = %d, want %d", got, catalog.NameValue())
}
if got := svc.GetNameValue(); got != catalog.NameValue() {
t.Fatalf("GetNameValue() = %d, want %d", got, catalog.NameValue())
}
if got := svc.RootValue(); got != catalog.RootValue() {
t.Fatalf("RootValue() = %d, want %d", got, catalog.RootValue())
}
if got := svc.GetRootValue(); got != catalog.RootValue() {
t.Fatalf("GetRootValue() = %d, want %d", got, catalog.RootValue())
}
if got := svc.TopValue(); got != catalog.TopValue() {
t.Fatalf("TopValue() = %d, want %d", got, catalog.TopValue())
}
if got := svc.GetTopValue(); got != catalog.TopValue() {
t.Fatalf("GetTopValue() = %d, want %d", got, catalog.TopValue())
}
if got := svc.PrefixSize(); got != catalog.PrefixSize() {
t.Fatalf("PrefixSize() = %d, want %d", got, catalog.PrefixSize())
}
if got := svc.GetPrefixSize(); got != catalog.PrefixSize() {
t.Fatalf("GetPrefixSize() = %d, want %d", got, catalog.PrefixSize())
}
if got := svc.ReservedPrefixSize(); got != catalog.PrefixSize() {
t.Fatalf("ReservedPrefixSize() = %d, want %d", got, catalog.PrefixSize())
}
if got := svc.GetReservedPrefixSize(); got != catalog.PrefixSize() {
t.Fatalf("GetReservedPrefixSize() = %d, want %d", got, catalog.PrefixSize())
}
if !catalog.HasByName("RESERVED") {
t.Fatal("ReservedCatalog should expose the reserved catalog helpers")
}
if len(catalog.Keys()) == 0 {
t.Fatal("ReservedCatalog should expose hash lookup aliases")
}
if !catalog.HasByHash(catalog.Keys()[0]) {
t.Fatal("ReservedCatalog should expose hash lookup aliases")
}
if _, ok := catalog.GetByHash(catalog.Keys()[0]); !ok {
t.Fatal("ReservedCatalog should expose hash lookup aliases")
}
if len(catalog.Entries()) == 0 {
t.Fatal("ReservedCatalog should expose catalog entries")
}
if len(svc.ReservedEntries()) == 0 {
t.Fatal("ReservedEntries should expose catalog entries")
}
if len(svc.GetReservedEntries()) == 0 {
t.Fatal("GetReservedEntries should expose catalog entries")
}
if len(svc.ReservedKeys()) == 0 {
t.Fatal("ReservedKeys should expose catalog keys")
}
if len(svc.GetReservedKeys()) == 0 {
t.Fatal("GetReservedKeys should expose catalog keys")
}
if len(svc.ReservedValues()) == 0 {
t.Fatal("ReservedValues should expose catalog values")
}
if len(svc.GetReservedValues()) == 0 {
t.Fatal("GetReservedValues should expose catalog values")
}
}
func TestServiceLockedCatalog(t *testing.T) {
svc := &Service{}
catalog := svc.LockedCatalog()
getCatalog := svc.GetLockedCatalog()
defaultCatalog := DefaultLockedCatalog()
packageGetCatalog := GetLockedCatalog()
if catalog == nil {
t.Fatal("LockedCatalog should return a catalog")
}
if getCatalog == nil {
t.Fatal("GetLockedCatalog should return a catalog")
}
if catalog != Locked {
t.Fatal("LockedCatalog should return the exported Locked instance")
}
if getCatalog != catalog {
t.Fatal("GetLockedCatalog should alias LockedCatalog")
}
if defaultCatalog != catalog {
t.Fatal("DefaultLockedCatalog should alias the covenant default catalog")
}
if packageGetCatalog != catalog {
t.Fatal("GetLockedCatalog should alias DefaultLockedCatalog")
}
if got := svc.LockedSize(); got != catalog.Size() {
t.Fatalf("LockedSize() = %d, want %d", got, catalog.Size())
}
if got := svc.GetLockedSize(); got != catalog.Size() {
t.Fatalf("GetLockedSize() = %d, want %d", got, catalog.Size())
}
if got := svc.LockedPrefixSize(); got != catalog.PrefixSize() {
t.Fatalf("LockedPrefixSize() = %d, want %d", got, catalog.PrefixSize())
}
if got := svc.GetLockedPrefixSize(); got != catalog.PrefixSize() {
t.Fatalf("GetLockedPrefixSize() = %d, want %d", got, catalog.PrefixSize())
}
if !catalog.HasByName("NEC") {
t.Fatal("LockedCatalog should expose the locked catalog helpers")
}
if len(catalog.Keys()) == 0 {
t.Fatal("LockedCatalog should expose hash lookup aliases")
}
if !catalog.HasByHash(catalog.Keys()[0]) {
t.Fatal("LockedCatalog should expose hash lookup aliases")
}
if _, ok := catalog.GetByHash(catalog.Keys()[0]); !ok {
t.Fatal("LockedCatalog should expose hash lookup aliases")
}
if len(catalog.Entries()) == 0 {
t.Fatal("LockedCatalog should expose catalog entries")
}
if len(svc.LockedEntries()) == 0 {
t.Fatal("LockedEntries should expose catalog entries")
}
if len(svc.GetLockedEntries()) == 0 {
t.Fatal("GetLockedEntries should expose catalog entries")
}
if len(svc.LockedKeys()) == 0 {
t.Fatal("LockedKeys should expose catalog keys")
}
if len(svc.GetLockedKeys()) == 0 {
t.Fatal("GetLockedKeys should expose catalog keys")
}
if len(svc.LockedValues()) == 0 {
t.Fatal("LockedValues should expose catalog values")
}
if len(svc.GetLockedValues()) == 0 {
t.Fatal("GetLockedValues should expose catalog values")
}
}
func TestServiceNameSetHelpers(t *testing.T) {
svc := &Service{}
hash, err := svc.HashString("example-name")
if err != nil {
t.Fatalf("HashString returned error: %v", err)
}
tx := primitives.Transaction{
Inputs: []primitives.Input{
{Prevout: primitives.Outpoint{TxHash: primitives.Hash{1}, Index: 0}},
},
Outputs: []primitives.Output{
{Covenant: primitives.Covenant{Type: uint8(covenant.TypeOpen), Items: [][]byte{hash[:], []byte{0, 0, 0, 0}, []byte("example-name")}}},
},
}
set := map[primitives.Hash]struct{}{
hash: {},
}
if !svc.HasNames(tx, set) {
t.Fatal("HasNames should report a matching name hash")
}
if !svc.GetHasNames(tx, set) {
t.Fatal("GetHasNames should report a matching name hash")
}
svc.RemoveNames(tx, set)
svc.GetRemoveNames(tx, set)
if len(set) != 0 {
t.Fatalf("RemoveNames/GetRemoveNames left %d entries, want 0", len(set))
}
svc.AddNames(tx, set)
svc.GetAddNames(tx, set)
if len(set) != 1 {
t.Fatalf("AddNames/GetAddNames left %d entries, want 1", len(set))
}
}
func TestServiceVerifyCovenants(t *testing.T) {
svc := &Service{}
hash, err := covenant.HashString("example-name")
if err != nil {
t.Fatalf("HashString returned error: %v", err)
}
var prevHash primitives.Hash
prevHash[0] = 5
var finalHash primitives.Hash
finalHash[0] = 6
committedAddress := append([]byte(nil), finalHash[:]...)
outputAddress := append([]byte(nil), finalHash[:]...)
transferCovenant := primitives.Covenant{
Type: uint8(covenant.TypeTransfer),
Items: [][]byte{
hash[:],
make([]byte, 4),
[]byte{0},
committedAddress,
},
}
binary.LittleEndian.PutUint32(transferCovenant.Items[1], 100)
finalizeCovenant := primitives.Covenant{
Type: uint8(covenant.TypeFinalize),
Items: [][]byte{
hash[:],
make([]byte, 4),
[]byte("example-name"),
[]byte{0},
make([]byte, 4),
make([]byte, 4),
make([]byte, 32),
},
}
binary.LittleEndian.PutUint32(finalizeCovenant.Items[1], 100)
binary.LittleEndian.PutUint32(finalizeCovenant.Items[4], 1)
binary.LittleEndian.PutUint32(finalizeCovenant.Items[5], 2)
tx := primitives.Transaction{
Inputs: []primitives.Input{
{Prevout: primitives.Outpoint{TxHash: prevHash, Index: 0}},
},
Outputs: []primitives.Output{
{
Value: 1000,
Address: primitives.Address{
Version: 0,
Hash: outputAddress,
},
Covenant: finalizeCovenant,
},
},
}
if !svc.HasSaneCovenants(tx) {
t.Fatal("HasSaneCovenants should accept structurally valid covenants")
}
if !svc.GetHasSaneCovenants(tx) {
t.Fatal("GetHasSaneCovenants should accept structurally valid covenants")
}
view := packageTestCoinView{
coins: map[primitives.Outpoint]primitives.Output{
primitives.Outpoint{TxHash: prevHash, Index: 0}: primitives.Output{
Value: 1000,
Address: primitives.Address{
Version: 0,
Hash: []byte{9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9},
},
Covenant: transferCovenant,
},
},
}
if got := svc.VerifyCovenants(tx, view, 100, Network{}); got != 0 {
t.Fatalf("VerifyCovenants returned %d, want 0", got)
}
tx.Outputs[0].Address.Hash[0] ^= 1
if got := svc.GetVerifyCovenants(tx, view, 100, Network{}); got != -1 {
t.Fatalf("GetVerifyCovenants returned %d for an invalid finalize address, want -1", got)
}
}