mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-01-12 16:53:21 +08:00
tests: migrate core contracts test to clarinet-sdk
This commit is contained in:
@@ -145,12 +145,15 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
- name: Execute core contract unit tests in Clarinet
|
||||
id: clarinet_unit_test
|
||||
uses: docker://hirosystems/clarinet:1.1.0
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
args: test --coverage --manifest-path=./contrib/core-contract-tests/Clarinet.toml
|
||||
node-version: 18.x
|
||||
cache: "npm"
|
||||
- run: npm ci
|
||||
- run: npm test
|
||||
- name: Export code coverage
|
||||
id: clarinet_codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./coverage.lcov
|
||||
files: ./lcov.info
|
||||
verbose: true
|
||||
|
||||
144
Cargo.lock
generated
144
Cargo.lock
generated
@@ -450,6 +450,28 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
"peeking_take_while",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"syn 1.0.109",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -584,6 +606,15 @@ version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
@@ -636,6 +667,17 @@ dependencies = [
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
@@ -1417,6 +1459,12 @@ version = "0.27.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "gloo-timers"
|
||||
version = "0.2.6"
|
||||
@@ -1878,10 +1926,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.140"
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||
|
||||
[[package]]
|
||||
name = "libflate"
|
||||
@@ -1903,6 +1957,16 @@ dependencies = [
|
||||
"rle-decode-fast",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libsigner"
|
||||
version = "0.0.1"
|
||||
@@ -1963,6 +2027,12 @@ version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
@@ -2022,6 +2092,12 @@ dependencies = [
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.6.2"
|
||||
@@ -2134,6 +2210,16 @@ dependencies = [
|
||||
"memoffset 0.6.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
@@ -2268,7 +2354,10 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
[[package]]
|
||||
name = "p256k1"
|
||||
version = "5.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22e81c2cb5a1936d3f26278f9d698932239d03ddf0d5818392d91cd5f98ffc79"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"bitvec",
|
||||
"bs58 0.4.0",
|
||||
"cc",
|
||||
@@ -2317,6 +2406,12 @@ version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.2.0"
|
||||
@@ -2879,6 +2974,12 @@ version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hex"
|
||||
version = "2.1.0"
|
||||
@@ -2935,10 +3036,23 @@ dependencies = [
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"linux-raw-sys 0.3.8",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.10",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.21.7"
|
||||
@@ -3283,6 +3397,12 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380"
|
||||
|
||||
[[package]]
|
||||
name = "simple-mutex"
|
||||
version = "1.1.5"
|
||||
@@ -3671,7 +3791,7 @@ dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"fastrand",
|
||||
"redox_syscall 0.3.5",
|
||||
"rustix",
|
||||
"rustix 0.37.7",
|
||||
"windows-sys 0.45.0",
|
||||
]
|
||||
|
||||
@@ -4352,6 +4472,18 @@ version = "0.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc"
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
|
||||
dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"once_cell",
|
||||
"rustix 0.38.21",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
@@ -4574,6 +4706,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "wsts"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a0c0ec44cbd35be82490c8c566ad4971f7b41ffe8508f1c9938140df7fe18b2"
|
||||
dependencies = [
|
||||
"aes-gcm 0.10.2",
|
||||
"bs58 0.5.0",
|
||||
|
||||
7
contrib/core-contract-tests/.gitignore
vendored
Normal file
7
contrib/core-contract-tests/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
coverage
|
||||
*.info
|
||||
costs-reports.json
|
||||
node_modules
|
||||
1812
contrib/core-contract-tests/package-lock.json
generated
Normal file
1812
contrib/core-contract-tests/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
20
contrib/core-contract-tests/package.json
Normal file
20
contrib/core-contract-tests/package.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "core-contract-tests-tests",
|
||||
"version": "1.0.0",
|
||||
"description": "Run unit tests on this project.",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "vitest run -- --coverage"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@hirosystems/clarinet-sdk": "^1.1.0",
|
||||
"@stacks/transactions": "^6.9.0",
|
||||
"chokidar-cli": "^3.0.0",
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^4.4.9",
|
||||
"vitest": "^0.34.4",
|
||||
"vitest-environment-clarinet": "^1.0.0"
|
||||
}
|
||||
}
|
||||
597
contrib/core-contract-tests/tests/bns/name_register.test.ts
Normal file
597
contrib/core-contract-tests/tests/bns/name_register.test.ts
Normal file
@@ -0,0 +1,597 @@
|
||||
import { Cl } from "@stacks/transactions";
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { createHash } from "node:crypto";
|
||||
|
||||
const accounts = simnet.getAccounts();
|
||||
const alice = accounts.get("wallet_1")!;
|
||||
const bob = accounts.get("wallet_2")!;
|
||||
const charlie = accounts.get("wallet_3")!;
|
||||
|
||||
const cases = [
|
||||
{
|
||||
namespace: "blockstack",
|
||||
version: 1,
|
||||
salt: "0000",
|
||||
value: 640000000,
|
||||
namespaceOwner: alice,
|
||||
nameOwner: bob,
|
||||
priceFunction: [
|
||||
Cl.uint(4), // base
|
||||
Cl.uint(250), // coeff
|
||||
Cl.uint(7), // bucket 1
|
||||
Cl.uint(6), // bucket 2
|
||||
Cl.uint(5), // bucket 3
|
||||
Cl.uint(4), // bucket 4
|
||||
Cl.uint(3), // bucket 5
|
||||
Cl.uint(2), // bucket 6
|
||||
Cl.uint(1), // bucket 7
|
||||
Cl.uint(1), // bucket 8
|
||||
Cl.uint(1), // bucket 9
|
||||
Cl.uint(1), // bucket 10
|
||||
Cl.uint(1), // bucket 11
|
||||
Cl.uint(1), // bucket 12
|
||||
Cl.uint(1), // bucket 13
|
||||
Cl.uint(1), // bucket 14
|
||||
Cl.uint(1), // bucket 15
|
||||
Cl.uint(1), // bucket 16+
|
||||
Cl.uint(4), // nonAlphaDiscount
|
||||
Cl.uint(4), // noVowelDiscount
|
||||
],
|
||||
renewalRule: 10,
|
||||
nameImporter: alice,
|
||||
zonefile: "0000",
|
||||
},
|
||||
{
|
||||
namespace: "id",
|
||||
version: 1,
|
||||
salt: "0000",
|
||||
value: 64000000000,
|
||||
namespaceOwner: alice,
|
||||
nameOwner: bob,
|
||||
priceFunction: [
|
||||
Cl.uint(4), // base
|
||||
Cl.uint(250), // coeff
|
||||
Cl.uint(6), // bucket 1
|
||||
Cl.uint(5), // bucket 2
|
||||
Cl.uint(4), // bucket 3
|
||||
Cl.uint(3), // bucket 4
|
||||
Cl.uint(2), // bucket 5
|
||||
Cl.uint(1), // bucket 6
|
||||
Cl.uint(0), // bucket 7
|
||||
Cl.uint(0), // bucket 8
|
||||
Cl.uint(0), // bucket 9
|
||||
Cl.uint(0), // bucket 10
|
||||
Cl.uint(0), // bucket 11
|
||||
Cl.uint(0), // bucket 12
|
||||
Cl.uint(0), // bucket 13
|
||||
Cl.uint(0), // bucket 14
|
||||
Cl.uint(0), // bucket 15
|
||||
Cl.uint(0), // bucket 16+
|
||||
Cl.uint(20), // nonAlphaDiscount
|
||||
Cl.uint(20), // noVowelDiscount
|
||||
],
|
||||
renewalRule: 20,
|
||||
nameImporter: alice,
|
||||
zonefile: "1111",
|
||||
},
|
||||
];
|
||||
|
||||
describe("test bns contract namespace errors", () => {
|
||||
it("should throw ERR_NAMESPACE_BLANK", () => {
|
||||
const { result } = simnet.callReadOnlyFn(
|
||||
"bns",
|
||||
"resolve-principal",
|
||||
[Cl.standardPrincipal(bob)],
|
||||
alice
|
||||
);
|
||||
expect(result).toBeErr(
|
||||
Cl.tuple({
|
||||
code: Cl.int(2013),
|
||||
name: Cl.none(),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("should throw ERR_NAMESPACE_NOT_FOUND", () => {
|
||||
const { result } = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-register",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[1].namespace),
|
||||
Cl.bufferFromUtf8("bob"),
|
||||
Cl.bufferFromUtf8(cases[1].salt),
|
||||
Cl.bufferFromUtf8(cases[1].zonefile),
|
||||
],
|
||||
cases[0].nameOwner
|
||||
);
|
||||
|
||||
expect(result).toBeErr(Cl.int(1005));
|
||||
});
|
||||
});
|
||||
|
||||
describe("preorder namespace", () => {
|
||||
it("should preorder a namespace", () => {
|
||||
const merged = new TextEncoder().encode(`${cases[1].namespace}${cases[1].salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
const { result } = simnet.callPublicFn(
|
||||
"bns",
|
||||
"namespace-preorder",
|
||||
[Cl.buffer(ripemd160), Cl.uint(cases[1].value)],
|
||||
cases[1].namespaceOwner
|
||||
);
|
||||
expect(result).toBeOk(Cl.uint(144 + simnet.blockHeight));
|
||||
});
|
||||
});
|
||||
|
||||
describe("namespace reveal workflow", () => {
|
||||
// preorder namespace
|
||||
beforeEach(() => {
|
||||
const merged = new TextEncoder().encode(`${cases[1].namespace}${cases[1].salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
const { result } = simnet.callPublicFn(
|
||||
"bns",
|
||||
"namespace-preorder",
|
||||
[Cl.buffer(ripemd160), Cl.uint(cases[1].value)],
|
||||
cases[1].namespaceOwner
|
||||
);
|
||||
expect(result).toBeOk(Cl.uint(144 + simnet.blockHeight));
|
||||
});
|
||||
|
||||
it("should reveal a namespace", () => {
|
||||
const { result } = simnet.callPublicFn(
|
||||
"bns",
|
||||
"namespace-reveal",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[1].namespace),
|
||||
Cl.bufferFromUtf8(cases[1].salt),
|
||||
...cases[1].priceFunction,
|
||||
Cl.uint(cases[1].renewalRule),
|
||||
Cl.standardPrincipal(cases[1].nameImporter),
|
||||
],
|
||||
cases[1].namespaceOwner
|
||||
);
|
||||
|
||||
expect(result).toBeOk(Cl.bool(true));
|
||||
});
|
||||
|
||||
it("fails if the namespace is not revealed", () => {
|
||||
simnet.callPublicFn(
|
||||
"bns",
|
||||
"namespace-reveal",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[1].namespace),
|
||||
Cl.bufferFromUtf8(cases[1].salt),
|
||||
...cases[1].priceFunction,
|
||||
Cl.uint(cases[1].renewalRule),
|
||||
Cl.standardPrincipal(cases[1].nameImporter),
|
||||
],
|
||||
cases[1].namespaceOwner
|
||||
);
|
||||
|
||||
const name = "baobab";
|
||||
const merged = new TextEncoder().encode(`${name}.${cases[1].namespace}${cases[1].salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
const preorder = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-preorder",
|
||||
[Cl.buffer(ripemd160), Cl.uint(100)],
|
||||
bob
|
||||
);
|
||||
expect(preorder.result).toBeOk(Cl.uint(144 + simnet.blockHeight));
|
||||
|
||||
const register = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-register",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[1].namespace),
|
||||
Cl.bufferFromUtf8(name),
|
||||
Cl.bufferFromUtf8(cases[1].salt),
|
||||
Cl.bufferFromUtf8(cases[1].zonefile),
|
||||
],
|
||||
bob
|
||||
);
|
||||
expect(register.result).toBeErr(Cl.int(2004));
|
||||
});
|
||||
|
||||
it("can launch a namespace", () => {
|
||||
const merged = new TextEncoder().encode(`${cases[0].namespace}${cases[0].salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
simnet.callPublicFn(
|
||||
"bns",
|
||||
"namespace-preorder",
|
||||
[Cl.buffer(ripemd160), Cl.uint(cases[0].value)],
|
||||
cases[0].namespaceOwner
|
||||
);
|
||||
|
||||
simnet.callPublicFn(
|
||||
"bns",
|
||||
"namespace-reveal",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[0].namespace),
|
||||
Cl.bufferFromUtf8(cases[0].salt),
|
||||
...cases[0].priceFunction,
|
||||
Cl.uint(cases[0].renewalRule),
|
||||
Cl.standardPrincipal(cases[0].nameImporter),
|
||||
],
|
||||
cases[0].namespaceOwner
|
||||
);
|
||||
|
||||
const { result } = simnet.callPublicFn(
|
||||
"bns",
|
||||
"namespace-ready",
|
||||
[Cl.bufferFromUtf8(cases[0].namespace)],
|
||||
cases[0].namespaceOwner
|
||||
);
|
||||
expect(result).toBeOk(Cl.bool(true));
|
||||
});
|
||||
});
|
||||
|
||||
describe("name revealing workflow", () => {
|
||||
beforeEach(() => {
|
||||
// launch namespace
|
||||
const merged = new TextEncoder().encode(`${cases[0].namespace}${cases[0].salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
simnet.callPublicFn(
|
||||
"bns",
|
||||
"namespace-preorder",
|
||||
[Cl.buffer(ripemd160), Cl.uint(cases[0].value)],
|
||||
cases[0].namespaceOwner
|
||||
);
|
||||
|
||||
simnet.callPublicFn(
|
||||
"bns",
|
||||
"namespace-reveal",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[0].namespace),
|
||||
Cl.bufferFromUtf8(cases[0].salt),
|
||||
...cases[0].priceFunction,
|
||||
Cl.uint(cases[0].renewalRule),
|
||||
Cl.standardPrincipal(cases[0].nameImporter),
|
||||
],
|
||||
cases[0].namespaceOwner
|
||||
);
|
||||
|
||||
const { result } = simnet.callPublicFn(
|
||||
"bns",
|
||||
"namespace-ready",
|
||||
[Cl.bufferFromUtf8(cases[0].namespace)],
|
||||
cases[0].namespaceOwner
|
||||
);
|
||||
expect(result).toBeOk(Cl.bool(true));
|
||||
});
|
||||
|
||||
it("should fail if no preorder", () => {
|
||||
const name = "bob";
|
||||
const { result } = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-register",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[0].namespace),
|
||||
Cl.bufferFromUtf8(name),
|
||||
Cl.bufferFromUtf8(cases[0].salt),
|
||||
Cl.bufferFromUtf8(cases[0].zonefile),
|
||||
],
|
||||
bob
|
||||
);
|
||||
expect(result).toBeErr(Cl.int(2001));
|
||||
});
|
||||
|
||||
it("should fail if stx burnt is too low", () => {
|
||||
const name = "bub";
|
||||
const merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${cases[0].salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
simnet.callPublicFn("bns", "name-preorder", [Cl.buffer(ripemd160), Cl.uint(2559999)], bob);
|
||||
|
||||
const { result } = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-register",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[0].namespace),
|
||||
Cl.bufferFromUtf8("bub"),
|
||||
Cl.bufferFromUtf8(cases[0].salt),
|
||||
Cl.bufferFromUtf8(cases[0].zonefile),
|
||||
],
|
||||
bob
|
||||
);
|
||||
expect(result).toBeErr(Cl.int(2007));
|
||||
});
|
||||
|
||||
it("should fail if existing pre-order", () => {
|
||||
const name = "Bob";
|
||||
const merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${cases[0].salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
simnet.callPublicFn("bns", "name-preorder", [Cl.buffer(ripemd160), Cl.uint(2560000)], bob);
|
||||
|
||||
const { result } = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-register",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[0].namespace),
|
||||
Cl.bufferFromUtf8(name),
|
||||
Cl.bufferFromUtf8(cases[0].salt),
|
||||
Cl.bufferFromUtf8(cases[0].zonefile),
|
||||
],
|
||||
bob
|
||||
);
|
||||
expect(result).toBeErr(Cl.int(2022));
|
||||
});
|
||||
|
||||
it("should successfully register", () => {
|
||||
const name = "bob";
|
||||
const merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${cases[0].salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
simnet.callPublicFn("bns", "name-preorder", [Cl.buffer(ripemd160), Cl.uint(2560000)], bob);
|
||||
|
||||
const register = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-register",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[0].namespace),
|
||||
Cl.bufferFromUtf8(name),
|
||||
Cl.bufferFromUtf8(cases[0].salt),
|
||||
Cl.bufferFromUtf8(cases[0].zonefile),
|
||||
],
|
||||
bob
|
||||
);
|
||||
expect(register.result).toBeOk(Cl.bool(true));
|
||||
|
||||
const resolvePrincipal = simnet.callReadOnlyFn(
|
||||
"bns",
|
||||
"resolve-principal",
|
||||
[Cl.standardPrincipal(bob)],
|
||||
alice
|
||||
);
|
||||
expect(resolvePrincipal.result).toBeOk(
|
||||
Cl.tuple({
|
||||
name: Cl.bufferFromUtf8("bob"),
|
||||
namespace: Cl.bufferFromUtf8("blockstack"),
|
||||
})
|
||||
);
|
||||
|
||||
const nameResolve = simnet.callReadOnlyFn(
|
||||
"bns",
|
||||
"name-resolve",
|
||||
[Cl.bufferFromUtf8(cases[0].namespace), Cl.bufferFromUtf8(name)],
|
||||
alice
|
||||
);
|
||||
expect(nameResolve.result).toBeOk(
|
||||
Cl.tuple({
|
||||
owner: Cl.standardPrincipal(bob),
|
||||
["zonefile-hash"]: Cl.bufferFromUtf8(cases[0].zonefile),
|
||||
["lease-ending-at"]: Cl.some(Cl.uint(16)),
|
||||
["lease-started-at"]: Cl.uint(6),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it("should fail registering twice", () => {
|
||||
const name = "bob";
|
||||
const merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${cases[0].salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
simnet.callPublicFn("bns", "name-preorder", [Cl.buffer(ripemd160), Cl.uint(2560000)], bob);
|
||||
simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-register",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[0].namespace),
|
||||
Cl.bufferFromUtf8(name),
|
||||
Cl.bufferFromUtf8(cases[0].salt),
|
||||
Cl.bufferFromUtf8(cases[0].zonefile),
|
||||
],
|
||||
bob
|
||||
);
|
||||
simnet.callReadOnlyFn("bns", "resolve-principal", [Cl.standardPrincipal(bob)], alice);
|
||||
|
||||
const { result } = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-register",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[0].namespace),
|
||||
Cl.bufferFromUtf8(name),
|
||||
Cl.bufferFromUtf8(cases[0].salt),
|
||||
Cl.bufferFromUtf8(cases[0].zonefile),
|
||||
],
|
||||
bob
|
||||
);
|
||||
expect(result).toBeErr(Cl.int(2004));
|
||||
});
|
||||
});
|
||||
|
||||
describe("register a name again before and after expiration", () => {
|
||||
beforeEach(() => {
|
||||
// launch namespace
|
||||
const mergedNS = new TextEncoder().encode(`${cases[0].namespace}${cases[0].salt}`);
|
||||
const sha256NS = createHash("sha256").update(mergedNS).digest();
|
||||
const ripemd160NS = createHash("ripemd160").update(sha256NS).digest();
|
||||
simnet.callPublicFn(
|
||||
"bns",
|
||||
"namespace-preorder",
|
||||
[Cl.buffer(ripemd160NS), Cl.uint(cases[0].value)],
|
||||
cases[0].namespaceOwner
|
||||
);
|
||||
|
||||
simnet.callPublicFn(
|
||||
"bns",
|
||||
"namespace-reveal",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[0].namespace),
|
||||
Cl.bufferFromUtf8(cases[0].salt),
|
||||
...cases[0].priceFunction,
|
||||
Cl.uint(cases[0].renewalRule),
|
||||
Cl.standardPrincipal(cases[0].nameImporter),
|
||||
],
|
||||
cases[0].namespaceOwner
|
||||
);
|
||||
|
||||
simnet.callPublicFn(
|
||||
"bns",
|
||||
"namespace-ready",
|
||||
[Cl.bufferFromUtf8(cases[0].namespace)],
|
||||
cases[0].namespaceOwner
|
||||
);
|
||||
|
||||
// register bob.blockstack
|
||||
const name = "bob";
|
||||
const merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${cases[0].salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
simnet.callPublicFn("bns", "name-preorder", [Cl.buffer(ripemd160), Cl.uint(2560000)], bob);
|
||||
|
||||
simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-register",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[0].namespace),
|
||||
Cl.bufferFromUtf8(name),
|
||||
Cl.bufferFromUtf8(cases[0].salt),
|
||||
Cl.bufferFromUtf8(cases[0].zonefile),
|
||||
],
|
||||
bob
|
||||
);
|
||||
});
|
||||
|
||||
it("fails if someone else tries to register it", () => {
|
||||
const name = "bob";
|
||||
let salt = "1111";
|
||||
const merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
const preorder = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-preorder",
|
||||
[Cl.buffer(ripemd160), Cl.uint(2560000)],
|
||||
charlie
|
||||
);
|
||||
expect(preorder.result).toBeOk(Cl.uint(144 + simnet.blockHeight));
|
||||
|
||||
const register = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-register",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[0].namespace),
|
||||
Cl.bufferFromUtf8(name),
|
||||
Cl.bufferFromUtf8(salt),
|
||||
Cl.bufferFromUtf8(cases[0].zonefile),
|
||||
],
|
||||
charlie
|
||||
);
|
||||
expect(register.result).toBeErr(Cl.int(2004));
|
||||
});
|
||||
|
||||
it("should fail to register to register two names", () => {
|
||||
const name = "bobby";
|
||||
const salt = "1111";
|
||||
const merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
simnet.callPublicFn("bns", "name-preorder", [Cl.buffer(ripemd160), Cl.uint(2560000)], bob);
|
||||
|
||||
const { result } = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-register",
|
||||
[
|
||||
Cl.bufferFromUtf8(cases[0].namespace),
|
||||
Cl.bufferFromUtf8(name),
|
||||
Cl.bufferFromUtf8(salt),
|
||||
Cl.bufferFromUtf8(cases[0].zonefile),
|
||||
],
|
||||
bob
|
||||
);
|
||||
expect(result).toBeErr(Cl.int(3001));
|
||||
});
|
||||
|
||||
it("should allow registering a new name after first name expiration", () => {
|
||||
simnet.mineEmptyBlocks(cases[0].renewalRule + 5001);
|
||||
|
||||
const resolve = simnet.callReadOnlyFn(
|
||||
"bns",
|
||||
"resolve-principal",
|
||||
[Cl.standardPrincipal(bob)],
|
||||
alice
|
||||
);
|
||||
expect(resolve.result).toBeErr(
|
||||
Cl.tuple({
|
||||
code: Cl.int(2008),
|
||||
name: Cl.some(
|
||||
Cl.tuple({
|
||||
name: Cl.bufferFromUtf8("bob"),
|
||||
namespace: Cl.bufferFromUtf8("blockstack"),
|
||||
})
|
||||
),
|
||||
})
|
||||
);
|
||||
|
||||
const name = "bobby";
|
||||
const salt = "1111";
|
||||
const merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
const preorder = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-preorder",
|
||||
[Cl.buffer(ripemd160), Cl.uint(2560000)],
|
||||
bob
|
||||
);
|
||||
expect(preorder.result).toBeOk(Cl.uint(144 + simnet.blockHeight));
|
||||
|
||||
const register = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-register",
|
||||
[
|
||||
Cl.bufferFromAscii(cases[0].namespace),
|
||||
Cl.bufferFromAscii(name),
|
||||
Cl.bufferFromAscii(salt),
|
||||
Cl.bufferFromAscii(cases[0].zonefile),
|
||||
],
|
||||
bob
|
||||
);
|
||||
expect(register.result).toBeOk(Cl.bool(true));
|
||||
});
|
||||
|
||||
it("should allow someone else to register after expiration", () => {
|
||||
simnet.mineEmptyBlocks(cases[0].renewalRule + 5001);
|
||||
|
||||
const name = "bob";
|
||||
const salt = "2222";
|
||||
const merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${salt}`);
|
||||
const sha256 = createHash("sha256").update(merged).digest();
|
||||
const ripemd160 = createHash("ripemd160").update(sha256).digest();
|
||||
simnet.callPublicFn("bns", "name-preorder", [Cl.buffer(ripemd160), Cl.uint(2560000)], charlie);
|
||||
const register = simnet.callPublicFn(
|
||||
"bns",
|
||||
"name-register",
|
||||
[
|
||||
Cl.bufferFromAscii(cases[0].namespace),
|
||||
Cl.bufferFromAscii(name),
|
||||
Cl.bufferFromAscii(salt),
|
||||
Cl.bufferFromAscii("CHARLIE"),
|
||||
],
|
||||
charlie
|
||||
);
|
||||
expect(register.result).toBeOk(Cl.bool(true));
|
||||
|
||||
const resolve = simnet.callReadOnlyFn(
|
||||
"bns",
|
||||
"name-resolve",
|
||||
[Cl.bufferFromAscii(cases[0].namespace), Cl.bufferFromAscii(name)],
|
||||
alice
|
||||
);
|
||||
expect(resolve.result).toBeOk(
|
||||
Cl.tuple({
|
||||
owner: Cl.standardPrincipal(charlie),
|
||||
["zonefile-hash"]: Cl.bufferFromAscii("CHARLIE"),
|
||||
["lease-ending-at"]: Cl.some(Cl.uint(5029)),
|
||||
["lease-started-at"]: Cl.uint(5019),
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,565 +0,0 @@
|
||||
import { Clarinet, Tx, Chain, Account, Contract, types } from 'https://deno.land/x/clarinet@v1.1.0/index.ts';
|
||||
import { assertEquals } from "https://deno.land/std@0.90.0/testing/asserts.ts";
|
||||
import { createHash } from "https://deno.land/std@0.107.0/hash/mod.ts";
|
||||
|
||||
Clarinet.test({
|
||||
name: "Ensure that name can be registered",
|
||||
async fn(chain: Chain, accounts: Map<string, Account>, contracts: Map<string, Contract>) {
|
||||
|
||||
const alice = accounts.get("wallet_1")!;
|
||||
const bob = accounts.get("wallet_2")!;
|
||||
const charlie = accounts.get("wallet_3")!;
|
||||
const dave = accounts.get("wallet_4")!;
|
||||
|
||||
const cases = [{
|
||||
namespace: "blockstack",
|
||||
version: 1,
|
||||
salt: "0000",
|
||||
value: 640000000,
|
||||
namespaceOwner: alice,
|
||||
nameOwner: bob,
|
||||
priceFunction: [
|
||||
types.uint(4), // base
|
||||
types.uint(250), // coeff
|
||||
types.uint(7), // bucket 1
|
||||
types.uint(6), // bucket 2
|
||||
types.uint(5), // bucket 3
|
||||
types.uint(4), // bucket 4
|
||||
types.uint(3), // bucket 5
|
||||
types.uint(2), // bucket 6
|
||||
types.uint(1), // bucket 7
|
||||
types.uint(1), // bucket 8
|
||||
types.uint(1), // bucket 9
|
||||
types.uint(1), // bucket 10
|
||||
types.uint(1), // bucket 11
|
||||
types.uint(1), // bucket 12
|
||||
types.uint(1), // bucket 13
|
||||
types.uint(1), // bucket 14
|
||||
types.uint(1), // bucket 15
|
||||
types.uint(1), // bucket 16+
|
||||
types.uint(4), // nonAlphaDiscount
|
||||
types.uint(4), // noVowelDiscount
|
||||
],
|
||||
renewalRule: 10,
|
||||
nameImporter: alice,
|
||||
zonefile: "0000",
|
||||
}, {
|
||||
namespace: "id",
|
||||
version: 1,
|
||||
salt: "0000",
|
||||
value: 64000000000,
|
||||
namespaceOwner: alice,
|
||||
nameOwner: bob,
|
||||
priceFunction: [
|
||||
types.uint(4), // base
|
||||
types.uint(250), // coeff
|
||||
types.uint(6), // bucket 1
|
||||
types.uint(5), // bucket 2
|
||||
types.uint(4), // bucket 3
|
||||
types.uint(3), // bucket 4
|
||||
types.uint(2), // bucket 5
|
||||
types.uint(1), // bucket 6
|
||||
types.uint(0), // bucket 7
|
||||
types.uint(0), // bucket 8
|
||||
types.uint(0), // bucket 9
|
||||
types.uint(0), // bucket 10
|
||||
types.uint(0), // bucket 11
|
||||
types.uint(0), // bucket 12
|
||||
types.uint(0), // bucket 13
|
||||
types.uint(0), // bucket 14
|
||||
types.uint(0), // bucket 15
|
||||
types.uint(0), // bucket 16+
|
||||
types.uint(20), // nonAlphaDiscount
|
||||
types.uint(20), // noVowelDiscount
|
||||
],
|
||||
renewalRule: 20,
|
||||
nameImporter: alice,
|
||||
zonefile: "1111",
|
||||
}];
|
||||
|
||||
let call = chain.callReadOnlyFn("bns", "resolve-principal", [types.principal(bob.address)], alice.address)
|
||||
let error:any = call.result
|
||||
.expectErr()
|
||||
.expectTuple();
|
||||
error['code'].expectInt(2013);
|
||||
|
||||
// Registering a name at this point should fail, namespace have not been registered yet
|
||||
let block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-register",
|
||||
[
|
||||
types.buff(cases[1].namespace),
|
||||
types.buff("bob"),
|
||||
types.buff(cases[1].salt),
|
||||
types.buff(cases[1].zonefile)
|
||||
],
|
||||
cases[0].nameOwner.address),
|
||||
]);
|
||||
assertEquals(block.height, 2);
|
||||
block.receipts[0].result
|
||||
.expectErr()
|
||||
.expectInt(1005);
|
||||
|
||||
// Preorder a namespace
|
||||
let merged = new TextEncoder().encode(`${cases[1].namespace}${cases[1].salt}`);
|
||||
let sha256 = createHash("sha256")
|
||||
.update(merged)
|
||||
.digest();
|
||||
let ripemd160 = createHash("ripemd160")
|
||||
.update(sha256)
|
||||
.digest();
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "namespace-preorder",
|
||||
[
|
||||
types.buff(ripemd160),
|
||||
types.uint(cases[1].value)
|
||||
],
|
||||
cases[1].namespaceOwner.address),
|
||||
]);
|
||||
assertEquals(block.height, 3);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectUint(144 + block.height - 1);
|
||||
|
||||
// Reveal the namespace
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "namespace-reveal",
|
||||
[
|
||||
types.buff(cases[1].namespace),
|
||||
types.buff(cases[1].salt),
|
||||
...cases[1].priceFunction,
|
||||
types.uint(cases[1].renewalRule),
|
||||
types.principal(cases[1].nameImporter.address),
|
||||
],
|
||||
cases[1].namespaceOwner.address),
|
||||
]);
|
||||
assertEquals(block.height, 4);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectBool(true);
|
||||
|
||||
// Bob can now preorder a name
|
||||
let name = "baobab";
|
||||
merged = new TextEncoder().encode(`${name}.${cases[1].namespace}${cases[1].salt}`);
|
||||
sha256 = createHash("sha256")
|
||||
.update(merged)
|
||||
.digest();
|
||||
ripemd160 = createHash("ripemd160")
|
||||
.update(sha256)
|
||||
.digest();
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-preorder",
|
||||
[
|
||||
types.buff(ripemd160),
|
||||
types.uint(100),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
assertEquals(block.height, 5);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectUint(144 + block.height - 1);
|
||||
|
||||
// But revealing the name should fail - the namespace was not launched yet
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-register",
|
||||
[
|
||||
types.buff(cases[1].namespace),
|
||||
types.buff(name),
|
||||
types.buff(cases[1].salt),
|
||||
types.buff(cases[1].zonefile),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
assertEquals(block.height, 6);
|
||||
block.receipts[0].result
|
||||
.expectErr()
|
||||
.expectInt(2004);
|
||||
|
||||
// // Given a launched namespace 'blockstack', owned by Alice
|
||||
merged = new TextEncoder().encode(`${cases[0].namespace}${cases[0].salt}`);
|
||||
sha256 = createHash("sha256")
|
||||
.update(merged)
|
||||
.digest();
|
||||
ripemd160 = createHash("ripemd160")
|
||||
.update(sha256)
|
||||
.digest();
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "namespace-preorder",
|
||||
[
|
||||
types.buff(ripemd160),
|
||||
types.uint(cases[0].value)
|
||||
],
|
||||
cases[0].namespaceOwner.address),
|
||||
]);
|
||||
assertEquals(block.height, 7);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectUint(144 + block.height - 1);
|
||||
|
||||
// Reveal the namespace
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "namespace-reveal",
|
||||
[
|
||||
types.buff(cases[0].namespace),
|
||||
types.buff(cases[0].salt),
|
||||
...cases[0].priceFunction,
|
||||
types.uint(cases[0].renewalRule),
|
||||
types.principal(cases[0].nameImporter.address),
|
||||
],
|
||||
cases[0].namespaceOwner.address),
|
||||
]);
|
||||
assertEquals(block.height, 8);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectBool(true);
|
||||
|
||||
// Launch the namespace
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "namespace-ready",
|
||||
[
|
||||
types.buff(cases[0].namespace),
|
||||
],
|
||||
cases[0].namespaceOwner.address),
|
||||
]);
|
||||
assertEquals(block.height, 9);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectBool(true);
|
||||
|
||||
// Revealing the name 'bob.blockstack'
|
||||
// should fail if no matching pre-order can be found
|
||||
// But revealing the name should fail - the namespace was not launched yet
|
||||
name = "bob";
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-register",
|
||||
[
|
||||
types.buff(cases[0].namespace),
|
||||
types.buff(name),
|
||||
types.buff(cases[0].salt),
|
||||
types.buff(cases[0].zonefile),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
assertEquals(block.height, 10);
|
||||
block.receipts[0].result
|
||||
.expectErr()
|
||||
.expectInt(2001);
|
||||
|
||||
// Bob can now preorder a name
|
||||
name = "bub";
|
||||
merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${cases[0].salt}`);
|
||||
sha256 = createHash("sha256")
|
||||
.update(merged)
|
||||
.digest();
|
||||
ripemd160 = createHash("ripemd160")
|
||||
.update(sha256)
|
||||
.digest();
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-preorder",
|
||||
[
|
||||
types.buff(ripemd160),
|
||||
types.uint(2559999),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
assertEquals(block.height, 11);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectUint(144 + block.height - 1);
|
||||
|
||||
// should fail
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-register",
|
||||
[
|
||||
types.buff(cases[0].namespace),
|
||||
types.buff("bub"),
|
||||
types.buff(cases[0].salt),
|
||||
types.buff(cases[0].zonefile),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
assertEquals(block.height, 12);
|
||||
block.receipts[0].result
|
||||
.expectErr()
|
||||
.expectInt(2007);
|
||||
|
||||
// Given an existing pre-order of the name 'Bob.blockstack'
|
||||
name = "Bob";
|
||||
merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${cases[0].salt}`);
|
||||
sha256 = createHash("sha256")
|
||||
.update(merged)
|
||||
.digest();
|
||||
ripemd160 = createHash("ripemd160")
|
||||
.update(sha256)
|
||||
.digest();
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-preorder",
|
||||
[
|
||||
types.buff(ripemd160),
|
||||
types.uint(2560000),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
assertEquals(block.height, 13);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectUint(144 + block.height - 1);
|
||||
|
||||
// Bob registering the name 'Bob.blockstack' should fail
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-register",
|
||||
[
|
||||
types.buff(cases[0].namespace),
|
||||
types.buff(name),
|
||||
types.buff(cases[0].salt),
|
||||
types.buff(cases[0].zonefile),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
assertEquals(block.height, 14);
|
||||
block.receipts[0].result
|
||||
.expectErr()
|
||||
.expectInt(2022);
|
||||
|
||||
// Given an existing pre-order of the name 'bob.blockstack'
|
||||
name = "bob";
|
||||
merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${cases[0].salt}`);
|
||||
sha256 = createHash("sha256")
|
||||
.update(merged)
|
||||
.digest();
|
||||
ripemd160 = createHash("ripemd160")
|
||||
.update(sha256)
|
||||
.digest();
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-preorder",
|
||||
[
|
||||
types.buff(ripemd160),
|
||||
types.uint(2560000),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
assertEquals(block.height, 15);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectUint(144 + block.height - 1);
|
||||
|
||||
// Bob registering the name 'bob.blockstack' should succeed
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-register",
|
||||
[
|
||||
types.buff(cases[0].namespace),
|
||||
types.buff(name),
|
||||
types.buff(cases[0].salt),
|
||||
types.buff(cases[0].zonefile),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
assertEquals(block.height, 16);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectBool(true);
|
||||
|
||||
call = chain.callReadOnlyFn("bns", "resolve-principal", [types.principal(bob.address)], alice.address)
|
||||
let response:any = call.result
|
||||
.expectOk()
|
||||
.expectTuple();
|
||||
response["name"].expectBuff("bob");
|
||||
response["namespace"].expectBuff("blockstack");
|
||||
|
||||
call = chain.callReadOnlyFn("bns", "name-resolve", [types.buff(cases[0].namespace), types.buff(name)], alice.address)
|
||||
response = call.result
|
||||
.expectOk()
|
||||
.expectTuple();
|
||||
response["owner"].expectPrincipal(bob.address);
|
||||
response["zonefile-hash"].expectBuff(cases[0].zonefile);
|
||||
|
||||
// should fail registering twice
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-register",
|
||||
[
|
||||
types.buff(cases[0].namespace),
|
||||
types.buff(name),
|
||||
types.buff(cases[0].salt),
|
||||
types.buff(cases[0].zonefile),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
assertEquals(block.height, 17);
|
||||
block.receipts[0].result
|
||||
.expectErr()
|
||||
.expectInt(2004);
|
||||
|
||||
// Charlie registering 'bob.blockstack'
|
||||
// should fail
|
||||
name = "bob";
|
||||
let salt = "1111"
|
||||
merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${salt}`);
|
||||
sha256 = createHash("sha256")
|
||||
.update(merged)
|
||||
.digest();
|
||||
ripemd160 = createHash("ripemd160")
|
||||
.update(sha256)
|
||||
.digest();
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-preorder",
|
||||
[
|
||||
types.buff(ripemd160),
|
||||
types.uint(2560000),
|
||||
],
|
||||
charlie.address),
|
||||
]);
|
||||
assertEquals(block.height, 18);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectUint(144 + block.height - 1);
|
||||
|
||||
// Bob registering the name 'bob.blockstack' should succeed
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-register",
|
||||
[
|
||||
types.buff(cases[0].namespace),
|
||||
types.buff(name),
|
||||
types.buff(salt),
|
||||
types.buff(cases[0].zonefile),
|
||||
],
|
||||
charlie.address),
|
||||
]);
|
||||
assertEquals(block.height, 19);
|
||||
block.receipts[0].result
|
||||
.expectErr()
|
||||
.expectInt(2004);
|
||||
|
||||
// Bob registering a second name 'bobby.blockstack'
|
||||
// should fail if 'bob.blockstack' is not expired
|
||||
name = "bobby";
|
||||
salt = "1111"
|
||||
merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${salt}`);
|
||||
sha256 = createHash("sha256")
|
||||
.update(merged)
|
||||
.digest();
|
||||
ripemd160 = createHash("ripemd160")
|
||||
.update(sha256)
|
||||
.digest();
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-preorder",
|
||||
[
|
||||
types.buff(ripemd160),
|
||||
types.uint(2560000),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
assertEquals(block.height, 20);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectUint(144 + block.height - 1);
|
||||
|
||||
// Bob registering the name 'bob.blockstack' should succeed
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-register",
|
||||
[
|
||||
types.buff(cases[0].namespace),
|
||||
types.buff(name),
|
||||
types.buff(salt),
|
||||
types.buff(cases[0].zonefile),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
assertEquals(block.height, 21);
|
||||
block.receipts[0].result
|
||||
.expectErr()
|
||||
.expectInt(3001);
|
||||
|
||||
// should succeed once 'bob.blockstack' is expired
|
||||
chain.mineEmptyBlock(cases[0].renewalRule + 5000);
|
||||
|
||||
call = chain.callReadOnlyFn("bns", "resolve-principal", [types.principal(bob.address)], alice.address)
|
||||
response = call.result
|
||||
.expectErr()
|
||||
.expectTuple();
|
||||
response["code"].expectInt("2008"); // Indicates ERR_NAME_EXPIRED
|
||||
let inner:any = response["name"].expectSome().expectTuple();
|
||||
inner["name"].expectBuff("bob");
|
||||
inner["namespace"].expectBuff("blockstack");
|
||||
|
||||
|
||||
name = "bobby";
|
||||
salt = "1111"
|
||||
merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${salt}`);
|
||||
sha256 = createHash("sha256")
|
||||
.update(merged)
|
||||
.digest();
|
||||
ripemd160 = createHash("ripemd160")
|
||||
.update(sha256)
|
||||
.digest();
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-preorder",
|
||||
[
|
||||
types.buff(ripemd160),
|
||||
types.uint(2560000),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectUint(144 + block.height - 1);
|
||||
|
||||
// Bob registering the name 'bobby.blockstack' should succeed
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-register",
|
||||
[
|
||||
types.buff(cases[0].namespace),
|
||||
types.buff(name),
|
||||
types.buff(salt),
|
||||
types.buff(cases[0].zonefile),
|
||||
],
|
||||
bob.address),
|
||||
]);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectBool(true);
|
||||
|
||||
// Charlie registering 'bob.blockstack'
|
||||
// should succeed once 'bob.blockstack' is expired
|
||||
name = "bob";
|
||||
salt = "2222"
|
||||
merged = new TextEncoder().encode(`${name}.${cases[0].namespace}${salt}`);
|
||||
sha256 = createHash("sha256")
|
||||
.update(merged)
|
||||
.digest();
|
||||
ripemd160 = createHash("ripemd160")
|
||||
.update(sha256)
|
||||
.digest();
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-preorder",
|
||||
[
|
||||
types.buff(ripemd160),
|
||||
types.uint(2560000),
|
||||
],
|
||||
charlie.address),
|
||||
]);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectUint(144 + block.height - 1);
|
||||
|
||||
block = chain.mineBlock([
|
||||
Tx.contractCall("bns", "name-register",
|
||||
[
|
||||
types.buff(cases[0].namespace),
|
||||
types.buff(name),
|
||||
types.buff(salt),
|
||||
types.buff("CHARLIE"),
|
||||
],
|
||||
charlie.address),
|
||||
]);
|
||||
block.receipts[0].result
|
||||
.expectOk()
|
||||
.expectBool(true);
|
||||
|
||||
call = chain.callReadOnlyFn("bns", "name-resolve", [types.buff(cases[0].namespace), types.buff(name)], alice.address)
|
||||
response = call.result
|
||||
.expectOk()
|
||||
.expectTuple();
|
||||
response["owner"].expectPrincipal(charlie.address);
|
||||
response["zonefile-hash"].expectBuff("CHARLIE");
|
||||
},
|
||||
});
|
||||
25
contrib/core-contract-tests/tsconfig.json
Normal file
25
contrib/core-contract-tests/tsconfig.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ESNext"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
|
||||
"strict": true,
|
||||
"noImplicitAny": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": [
|
||||
"node_modules/@hirosystems/clarinet-sdk/vitest-helpers/src",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
36
contrib/core-contract-tests/vitest.config.js
Normal file
36
contrib/core-contract-tests/vitest.config.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/// <reference types="vitest" />
|
||||
|
||||
import { defineConfig } from "vite";
|
||||
import { vitestSetupFilePath, getClarinetVitestsArgv } from "@hirosystems/clarinet-sdk/vitest";
|
||||
|
||||
/*
|
||||
In this file, Vitest is configured so that it works seamlessly with Clarinet and the Simnet.
|
||||
|
||||
The `vitest-environment-clarinet` will initialise the clarinet-sdk
|
||||
and make the `simnet` object available globally in the test files.
|
||||
|
||||
`vitestSetupFilePath` points to a file in the `@hirosystems/clarinet-sdk` package that does two things:
|
||||
- run `before` hooks to initialize the simnet and `after` hooks to collect costs and coverage reports.
|
||||
- load custom vitest matchers to work with Clarity values (such as `expect(...).toBeUint()`)
|
||||
|
||||
The `getClarinetVitestsArgv()` will parse options passed to the command `vitest run --`
|
||||
- vitest run -- --manifest ./Clarinet.toml # pass a custom path
|
||||
- vitest run -- --coverage --costs # collect coverage and cost reports
|
||||
*/
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
environment: "clarinet", // use vitest-environment-clarinet
|
||||
singleThread: true,
|
||||
setupFiles: [
|
||||
vitestSetupFilePath,
|
||||
// custom setup files can be added here
|
||||
],
|
||||
environmentOptions: {
|
||||
clarinet: {
|
||||
...getClarinetVitestsArgv(),
|
||||
// add or override options
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user