mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-04-24 03:45:38 +08:00
feat: feed BNS data in genesis block
This commit is contained in:
@@ -108,7 +108,7 @@ export class BNSClient extends Client {
|
||||
}
|
||||
|
||||
// (name-import (namespace (buff 20))
|
||||
// (name (buff 16))
|
||||
// (name (buff 48))
|
||||
// (zonefile-hash (buff 20)))
|
||||
async nameImport(namespace: string,
|
||||
name: string,
|
||||
@@ -168,7 +168,7 @@ export class BNSClient extends Client {
|
||||
}
|
||||
|
||||
// (name-register (namespace (buff 20))
|
||||
// (name (buff 16))
|
||||
// (name (buff 48))
|
||||
// (salt (buff 20))
|
||||
// (zonefile-hash (buff 20)))
|
||||
async nameRegister(namespace: string,
|
||||
@@ -190,7 +190,7 @@ export class BNSClient extends Client {
|
||||
}
|
||||
|
||||
// (name-update (namespace (buff 20))
|
||||
// (name (buff 16))
|
||||
// (name (buff 48))
|
||||
// (zonefile-hash (buff 20)))
|
||||
async nameUpdate(namespace: string,
|
||||
name: string,
|
||||
@@ -210,7 +210,7 @@ export class BNSClient extends Client {
|
||||
}
|
||||
|
||||
// (name-transfer (namespace (buff 20))
|
||||
// (name (buff 16))
|
||||
// (name (buff 48))
|
||||
// (new-owner principal)
|
||||
// (zonefile-hash (optional (buff 20))))
|
||||
async nameTransfer(namespace: string,
|
||||
@@ -235,7 +235,7 @@ export class BNSClient extends Client {
|
||||
}
|
||||
|
||||
// (name-revoke (namespace (buff 20))
|
||||
// (name (buff 16)))
|
||||
// (name (buff 48)))
|
||||
async nameRevoke(namespace: string,
|
||||
name: string,
|
||||
params: {
|
||||
@@ -253,7 +253,7 @@ export class BNSClient extends Client {
|
||||
}
|
||||
|
||||
// (name-renewal (namespace (buff 20))
|
||||
// (name (buff 16))
|
||||
// (name (buff 48))
|
||||
// (stx-to-burn uint)
|
||||
// (new-owner (optional principal))
|
||||
// (zonefile-hash (optional (buff 20))))
|
||||
@@ -281,7 +281,7 @@ export class BNSClient extends Client {
|
||||
}
|
||||
|
||||
// (get-name-zonefile (namespace (buff 20))
|
||||
// (name (buff 16)))
|
||||
// (name (buff 48)))
|
||||
async getNameZonefile(namespace: string,
|
||||
name: string,
|
||||
params: {
|
||||
@@ -299,7 +299,7 @@ export class BNSClient extends Client {
|
||||
}
|
||||
|
||||
// (can-name-be-registered (namespace (buff 20))
|
||||
// (name (buff 16))
|
||||
// (name (buff 48))
|
||||
async canNameBeRegistered(namespace: string,
|
||||
name: string): Promise<Receipt> {
|
||||
const args = [`0x${this.toHexString(namespace)}`, `0x${this.toHexString(name)}`];
|
||||
@@ -315,7 +315,7 @@ export class BNSClient extends Client {
|
||||
}
|
||||
|
||||
// (get-name-price (namespace (buff 20))
|
||||
// (name (buff 16))
|
||||
// (name (buff 48))
|
||||
async getNamePrice(namespace: string,
|
||||
name: string): Promise<Receipt> {
|
||||
const args = [`0x${this.toHexString(namespace)}`, `0x${this.toHexString(name)}`];
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
;;;; Data
|
||||
(define-map namespaces
|
||||
{ namespace: (buff 20) }
|
||||
(buff 20)
|
||||
{ namespace-import: principal,
|
||||
revealed-at: uint,
|
||||
launched-at: (optional uint),
|
||||
@@ -76,16 +76,16 @@
|
||||
{ hashed-salted-namespace: (buff 20), buyer: principal }
|
||||
{ created-at: uint, claimed: bool, stx-burned: uint })
|
||||
|
||||
(define-non-fungible-token names { name: (buff 32), namespace: (buff 20) })
|
||||
(define-non-fungible-token names { name: (buff 48), namespace: (buff 20) })
|
||||
|
||||
;; Rule 1-1 -> 1 principal, 1 name
|
||||
(define-map owner-name { owner: principal } { name: (buff 32), namespace: (buff 20) })
|
||||
(define-map owner-name principal { name: (buff 48), namespace: (buff 20) })
|
||||
;; Only applies to non-revoked, non-expired names.
|
||||
;; A principal can own many expired names (but they will be transferred away once someone re-registers them),
|
||||
;; and can own many revoked names (but they do not resolve and cannot be transferred or updated).
|
||||
|
||||
(define-map name-properties
|
||||
{ name: (buff 32), namespace: (buff 20) }
|
||||
{ name: (buff 48), namespace: (buff 20) }
|
||||
{ registered-at: (optional uint),
|
||||
imported-at: (optional uint),
|
||||
revoked-at: (optional uint),
|
||||
@@ -171,13 +171,13 @@
|
||||
(is-digit char)
|
||||
(is-special-char char)))
|
||||
|
||||
(define-private (has-vowels-chars (name (buff 32)))
|
||||
(define-private (has-vowels-chars (name (buff 48)))
|
||||
(> (len (filter is-vowel name)) u0))
|
||||
|
||||
(define-private (has-nonalpha-chars (name (buff 32)))
|
||||
(define-private (has-nonalpha-chars (name (buff 48)))
|
||||
(> (len (filter is-nonalpha name)) u0))
|
||||
|
||||
(define-private (has-invalid-chars (name (buff 32)))
|
||||
(define-private (has-invalid-chars (name (buff 48)))
|
||||
(< (len (filter is-char-valid name)) (len name)))
|
||||
|
||||
(define-private (name-lease-started-at? (namespace-launched-at (optional uint))
|
||||
@@ -216,7 +216,7 @@
|
||||
|
||||
;; Note: the following method is used in name-import and name-register. The latter ensure that the name
|
||||
;; can be registered, the former does not.
|
||||
(define-private (mint-or-transfer-name? (namespace (buff 20)) (name (buff 32)) (beneficiary principal))
|
||||
(define-private (mint-or-transfer-name? (namespace (buff 20)) (name (buff 48)) (beneficiary principal))
|
||||
(let (
|
||||
(current-owner (nft-get-owner? names (tuple (name name) (namespace namespace)))))
|
||||
;; The principal can register a name
|
||||
@@ -233,13 +233,13 @@
|
||||
beneficiary)
|
||||
(err ERR_NAME_COULD_NOT_BE_MINTED))
|
||||
(map-set owner-name
|
||||
{ owner: beneficiary }
|
||||
beneficiary
|
||||
{ name: name, namespace: namespace })
|
||||
(ok true))
|
||||
(update-name-ownership? namespace name (unwrap-panic current-owner) beneficiary))))
|
||||
|
||||
(define-private (update-name-ownership? (namespace (buff 20))
|
||||
(name (buff 32))
|
||||
(name (buff 48))
|
||||
(from principal)
|
||||
(to principal))
|
||||
(if (is-eq from to)
|
||||
@@ -248,14 +248,14 @@
|
||||
(unwrap!
|
||||
(nft-transfer? names { name: name, namespace: namespace } from to)
|
||||
(err ERR_NAME_COULD_NOT_BE_TRANSFERED))
|
||||
(map-delete owner-name { owner: from })
|
||||
(map-delete owner-name from)
|
||||
(map-set owner-name
|
||||
{ owner: to }
|
||||
to
|
||||
{ name: name, namespace: namespace })
|
||||
(ok true))))
|
||||
|
||||
(define-private (update-zonefile-and-props (namespace (buff 20))
|
||||
(name (buff 32))
|
||||
(name (buff 48))
|
||||
(registered-at (optional uint))
|
||||
(imported-at (optional uint))
|
||||
(revoked-at (optional uint))
|
||||
@@ -285,7 +285,7 @@
|
||||
zonefile-hash: zonefile-hash })))
|
||||
|
||||
(define-private (is-namespace-available (namespace (buff 20)))
|
||||
(match (map-get? namespaces { namespace: namespace }) namespace-props
|
||||
(match (map-get? namespaces namespace) namespace-props
|
||||
(begin
|
||||
;; Is the namespace launched?
|
||||
(if (is-some (get launched-at namespace-props))
|
||||
@@ -293,7 +293,7 @@
|
||||
(> block-height (+ (get revealed-at namespace-props) NAMESPACE_LAUNCHABILITY_TTL)))) ;; Is the namespace expired?
|
||||
true))
|
||||
|
||||
(define-private (compute-name-price (name (buff 32))
|
||||
(define-private (compute-name-price (name (buff 48))
|
||||
(price-function (tuple (buckets (list 16 uint))
|
||||
(base uint)
|
||||
(coeff uint)
|
||||
@@ -422,7 +422,7 @@
|
||||
;; The namespace will be set as "revealed" but not "launched", its price function, its renewal rules, its version,
|
||||
;; and its import principal will be written to the `namespaces` table.
|
||||
(map-set namespaces
|
||||
{ namespace: namespace }
|
||||
namespace
|
||||
{ namespace-import: namespace-import,
|
||||
revealed-at: block-height,
|
||||
launched-at: none,
|
||||
@@ -434,12 +434,12 @@
|
||||
;; Once a namespace is revealed, the user has the option to populate it with a set of names. Each imported name is given
|
||||
;; both an owner and some off-chain state. This step is optional; Namespace creators are not required to import names.
|
||||
(define-public (name-import (namespace (buff 20))
|
||||
(name (buff 32))
|
||||
(name (buff 48))
|
||||
(beneficiary principal)
|
||||
(zonefile-hash (buff 20)))
|
||||
(let (
|
||||
(namespace-props (unwrap!
|
||||
(map-get? namespaces { namespace: namespace })
|
||||
(map-get? namespaces namespace)
|
||||
(err ERR_NAMESPACE_NOT_FOUND))))
|
||||
;; The name must only have valid chars
|
||||
(asserts!
|
||||
@@ -476,7 +476,7 @@
|
||||
(define-public (namespace-ready (namespace (buff 20)))
|
||||
(let (
|
||||
(namespace-props (unwrap!
|
||||
(map-get? namespaces { namespace: namespace })
|
||||
(map-get? namespaces namespace)
|
||||
(err ERR_NAMESPACE_NOT_FOUND))))
|
||||
;; The sender principal must match the namespace's import principal
|
||||
(asserts!
|
||||
@@ -492,7 +492,7 @@
|
||||
(err ERR_NAMESPACE_PREORDER_LAUNCHABILITY_EXPIRED))
|
||||
(let ((namespace-props-updated (merge namespace-props { launched-at: (some block-height) })))
|
||||
;; The namespace will be set to "launched"
|
||||
(map-set namespaces { namespace: namespace } namespace-props-updated)
|
||||
(map-set namespaces namespace namespace-props-updated)
|
||||
;; Emit an event
|
||||
(print { namespace: namespace, status: "ready", properties: namespace-props-updated })
|
||||
(ok true))))
|
||||
@@ -531,13 +531,13 @@
|
||||
;; This is the second transaction to be sent. It reveals the salt and the name to all BNS nodes,
|
||||
;; and assigns the name an initial public key hash and zone file hash
|
||||
(define-public (name-register (namespace (buff 20))
|
||||
(name (buff 32))
|
||||
(name (buff 48))
|
||||
(salt (buff 20))
|
||||
(zonefile-hash (buff 20)))
|
||||
(let (
|
||||
(hashed-salted-fqn (hash160 (concat (concat (concat name 0x2e) namespace) salt)))
|
||||
(namespace-props (unwrap!
|
||||
(map-get? namespaces { namespace: namespace })
|
||||
(map-get? namespaces namespace)
|
||||
(err ERR_NAMESPACE_NOT_FOUND)))
|
||||
(preorder (unwrap!
|
||||
(map-get? name-preorders { hashed-salted-fqn: hashed-salted-fqn, buyer: tx-sender })
|
||||
@@ -579,7 +579,7 @@
|
||||
;; if you wanted to change the name's zone file contents.
|
||||
;; For example, you would do this if you want to deploy your own Gaia hub and want other people to read from it.
|
||||
(define-public (name-update (namespace (buff 20))
|
||||
(name (buff 32))
|
||||
(name (buff 48))
|
||||
(zonefile-hash (buff 20)))
|
||||
(let (
|
||||
(data (try! (check-name-ops-preconditions namespace name))))
|
||||
@@ -601,7 +601,7 @@
|
||||
;; When transferring a name, you have the option to also clear the name's zone file hash (i.e. set it to null).
|
||||
;; This is useful for when you send the name to someone else, so the recipient's name does not resolve to your zone file.
|
||||
(define-public (name-transfer (namespace (buff 20))
|
||||
(name (buff 32))
|
||||
(name (buff 48))
|
||||
(new-owner principal)
|
||||
(zonefile-hash (optional (buff 20))))
|
||||
(let (
|
||||
@@ -634,7 +634,7 @@
|
||||
;; The name's zone file hash is set to null to prevent it from resolving.
|
||||
;; You should only do this if your private key is compromised, or if you want to render your name unusable for whatever reason.
|
||||
(define-public (name-revoke (namespace (buff 20))
|
||||
(name (buff 32)))
|
||||
(name (buff 48)))
|
||||
(let (
|
||||
(data (try! (check-name-ops-preconditions namespace name))))
|
||||
;; Clear the zonefile
|
||||
@@ -657,13 +657,13 @@
|
||||
;; You may, however, send a NAME_RENEWAL during this grace period to preserve your name.
|
||||
;; If your name is in a namespace where names do not expire, then you never need to use this transaction.
|
||||
(define-public (name-renewal (namespace (buff 20))
|
||||
(name (buff 32))
|
||||
(name (buff 48))
|
||||
(stx-to-burn uint)
|
||||
(new-owner (optional principal))
|
||||
(zonefile-hash (optional (buff 20))))
|
||||
(let (
|
||||
(namespace-props (unwrap!
|
||||
(map-get? namespaces { namespace: namespace })
|
||||
(map-get? namespaces namespace)
|
||||
(err ERR_NAMESPACE_NOT_FOUND)))
|
||||
(owner (unwrap!
|
||||
(nft-get-owner? names { name: name, namespace: namespace })
|
||||
@@ -729,20 +729,20 @@
|
||||
(ok (unwrap-panic
|
||||
(element-at NAMESPACE_PRICE_TIERS (min u7 (- namespace-len u1)))))))
|
||||
|
||||
(define-read-only (get-name-price (namespace (buff 20)) (name (buff 32)))
|
||||
(define-read-only (get-name-price (namespace (buff 20)) (name (buff 48)))
|
||||
(let (
|
||||
(namespace-props (unwrap!
|
||||
(map-get? namespaces { namespace: namespace })
|
||||
(map-get? namespaces namespace)
|
||||
(err ERR_NAMESPACE_NOT_FOUND))))
|
||||
(ok (compute-name-price name (get price-function namespace-props)))))
|
||||
|
||||
(define-read-only (check-name-ops-preconditions (namespace (buff 20)) (name (buff 32)))
|
||||
(define-read-only (check-name-ops-preconditions (namespace (buff 20)) (name (buff 48)))
|
||||
(let (
|
||||
(owner (unwrap!
|
||||
(nft-get-owner? names { name: name, namespace: namespace })
|
||||
(err ERR_NAME_NOT_FOUND))) ;; The name must exist
|
||||
(namespace-props (unwrap!
|
||||
(map-get? namespaces { namespace: namespace })
|
||||
(map-get? namespaces namespace)
|
||||
(err ERR_NAMESPACE_NOT_FOUND)))
|
||||
(name-props (unwrap!
|
||||
(map-get? name-properties { name: name, namespace: namespace })
|
||||
@@ -772,10 +772,10 @@
|
||||
(define-read-only (can-namespace-be-registered (namespace (buff 20)))
|
||||
(ok (is-namespace-available namespace)))
|
||||
|
||||
(define-read-only (is-name-lease-expired (namespace (buff 20)) (name (buff 32)))
|
||||
(define-read-only (is-name-lease-expired (namespace (buff 20)) (name (buff 48)))
|
||||
(let (
|
||||
(namespace-props (unwrap!
|
||||
(map-get? namespaces { namespace: namespace })
|
||||
(map-get? namespaces namespace)
|
||||
(err ERR_NAMESPACE_NOT_FOUND)))
|
||||
(name-props (unwrap!
|
||||
(map-get? name-properties { name: name, namespace: namespace })
|
||||
@@ -786,10 +786,10 @@
|
||||
(ok false)
|
||||
(ok (> block-height (+ lifetime lease-started-at))))))
|
||||
|
||||
(define-read-only (is-name-in-grace-period (namespace (buff 20)) (name (buff 32)))
|
||||
(define-read-only (is-name-in-grace-period (namespace (buff 20)) (name (buff 48)))
|
||||
(let (
|
||||
(namespace-props (unwrap!
|
||||
(map-get? namespaces { namespace: namespace })
|
||||
(map-get? namespaces namespace)
|
||||
(err ERR_NAMESPACE_NOT_FOUND)))
|
||||
(name-props (unwrap!
|
||||
(map-get? name-properties { name: name, namespace: namespace })
|
||||
@@ -803,7 +803,7 @@
|
||||
(<= block-height (+ (+ lifetime lease-started-at) NAME_GRACE_PERIOD_DURATION)))))))
|
||||
|
||||
(define-read-only (can-receive-name (owner principal))
|
||||
(let ((current-owned-name (map-get? owner-name { owner: owner })))
|
||||
(let ((current-owned-name (map-get? owner-name owner)))
|
||||
(if (is-none current-owned-name)
|
||||
(ok true)
|
||||
(let (
|
||||
@@ -822,10 +822,10 @@
|
||||
(asserts! (is-some (get revoked-at name-props)) (ok false))
|
||||
(ok true))))))))
|
||||
|
||||
(define-read-only (can-name-be-registered (namespace (buff 20)) (name (buff 32)))
|
||||
(define-read-only (can-name-be-registered (namespace (buff 20)) (name (buff 48)))
|
||||
(let (
|
||||
(wrapped-name-props (map-get? name-properties { name: name, namespace: namespace }))
|
||||
(namespace-props (unwrap! (map-get? namespaces { namespace: namespace }) (ok false))))
|
||||
(namespace-props (unwrap! (map-get? namespaces namespace) (ok false))))
|
||||
;; The name must only have valid chars
|
||||
(asserts!
|
||||
(not (has-invalid-chars name))
|
||||
@@ -842,7 +842,7 @@
|
||||
;; Is lease expired?
|
||||
(is-name-lease-expired namespace name))))
|
||||
|
||||
(define-read-only (name-resolve (namespace (buff 20)) (name (buff 32)))
|
||||
(define-read-only (name-resolve (namespace (buff 20)) (name (buff 48)))
|
||||
(let (
|
||||
(owner (unwrap!
|
||||
(nft-get-owner? names { name: name, namespace: namespace })
|
||||
@@ -851,7 +851,7 @@
|
||||
(map-get? name-properties { name: name, namespace: namespace })
|
||||
(err ERR_NAME_NOT_FOUND)))
|
||||
(namespace-props (unwrap!
|
||||
(map-get? namespaces { namespace: namespace })
|
||||
(map-get? namespaces namespace)
|
||||
(err ERR_NAMESPACE_NOT_FOUND))))
|
||||
;; The name must not be in grace period
|
||||
(asserts!
|
||||
|
||||
@@ -630,6 +630,29 @@ pub struct ChainstateAccountLockup {
|
||||
pub block_height: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ChainstateBNSNamespace {
|
||||
pub namespace_id: String,
|
||||
pub importer: String,
|
||||
pub revealed_at: u64,
|
||||
pub launched_at: u64,
|
||||
pub buckets: String,
|
||||
pub base: u64,
|
||||
pub coeff: u64,
|
||||
pub nonalpha_discount: u64,
|
||||
pub no_vowel_discount: u64,
|
||||
pub lifetime: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ChainstateBNSName {
|
||||
pub fully_qualified_name: String,
|
||||
pub owner: String,
|
||||
pub registered_at: u64,
|
||||
pub expired_at: u64,
|
||||
pub zonefile_hash: String,
|
||||
}
|
||||
|
||||
impl ChainstateAccountLockup {
|
||||
pub fn new(address: StacksAddress, amount: u64, block_height: u64) -> ChainstateAccountLockup {
|
||||
ChainstateAccountLockup {
|
||||
@@ -650,6 +673,10 @@ pub struct ChainStateBootData {
|
||||
Option<Box<dyn FnOnce() -> Box<dyn Iterator<Item = ChainstateAccountLockup>>>>,
|
||||
pub get_bulk_initial_balances:
|
||||
Option<Box<dyn FnOnce() -> Box<dyn Iterator<Item = ChainstateAccountBalance>>>>,
|
||||
pub get_bulk_initial_namespaces:
|
||||
Option<Box<dyn FnOnce() -> Box<dyn Iterator<Item = ChainstateBNSNamespace>>>>,
|
||||
pub get_bulk_initial_names:
|
||||
Option<Box<dyn FnOnce() -> Box<dyn Iterator<Item = ChainstateBNSName>>>>,
|
||||
}
|
||||
|
||||
impl ChainStateBootData {
|
||||
@@ -666,6 +693,8 @@ impl ChainStateBootData {
|
||||
post_flight_callback,
|
||||
get_bulk_initial_lockups: None,
|
||||
get_bulk_initial_balances: None,
|
||||
get_bulk_initial_namespaces: None,
|
||||
get_bulk_initial_names: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1001,6 +1030,148 @@ impl StacksChainState {
|
||||
});
|
||||
}
|
||||
|
||||
let bns_contract_id = boot_code_id("bns");
|
||||
if let Some(get_namespaces) = boot_data.get_bulk_initial_namespaces.take() {
|
||||
info!("Initializing chain with namespaces");
|
||||
clarity_tx.connection().as_transaction(|clarity| {
|
||||
clarity.with_clarity_db(|db| {
|
||||
|
||||
let initial_namespaces = get_namespaces();
|
||||
for entry in initial_namespaces {
|
||||
|
||||
let namespace = {
|
||||
let buffer = entry.namespace_id.as_bytes();
|
||||
Value::buff_from(buffer.to_vec())
|
||||
.expect("Invalid namespace")
|
||||
};
|
||||
|
||||
let importer = {
|
||||
let address = StacksChainState::parse_genesis_address(&entry.importer, mainnet);
|
||||
Value::Principal(address)
|
||||
};
|
||||
|
||||
let revealed_at = Value::UInt(entry.revealed_at.into());
|
||||
let launched_at = Value::UInt(entry.launched_at.into());
|
||||
let lifetime = Value::UInt(entry.lifetime.into());
|
||||
let price_function = {
|
||||
let base = Value::UInt(entry.base.into());
|
||||
let coeff = Value::UInt(entry.coeff.into());
|
||||
let nonalpha_discount = Value::UInt(entry.nonalpha_discount.into());
|
||||
let no_vowel_discount = Value::UInt(entry.no_vowel_discount.into());
|
||||
let buckets: Vec<_> = entry.buckets
|
||||
.split(";")
|
||||
.map(|e|
|
||||
Value::UInt(e.parse::<u64>().unwrap().into()))
|
||||
.collect();
|
||||
|
||||
TupleData::from_data(vec![
|
||||
("buckets".into(), Value::list_from(buckets).unwrap()),
|
||||
("base".into(), base),
|
||||
("coeff".into(), coeff),
|
||||
("nonalpha-discount".into(), nonalpha_discount),
|
||||
("no-vowel-discount".into(), no_vowel_discount),
|
||||
]).unwrap()
|
||||
};
|
||||
|
||||
let namespace_props = Value::Tuple(
|
||||
TupleData::from_data(vec![
|
||||
("revealed-at".into(), revealed_at),
|
||||
("launched-at".into(), Value::some(launched_at).unwrap()),
|
||||
("lifetime".into(), lifetime),
|
||||
("namespace-import".into(), importer),
|
||||
("price-function".into(), Value::Tuple(price_function)),
|
||||
])
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
db.insert_entry(
|
||||
&bns_contract_id,
|
||||
"namespaces",
|
||||
namespace,
|
||||
namespace_props,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(get_names) = boot_data.get_bulk_initial_names.take() {
|
||||
info!("Initializing chain with names");
|
||||
clarity_tx.connection().as_transaction(|clarity| {
|
||||
clarity.with_clarity_db(|db| {
|
||||
let initial_names = get_names();
|
||||
for entry in initial_names {
|
||||
let components: Vec<_> = entry.fully_qualified_name
|
||||
.split(".")
|
||||
.collect();
|
||||
|
||||
let namespace = {
|
||||
let buffer = components[1].as_bytes();
|
||||
Value::buff_from(buffer.to_vec())
|
||||
.expect("Invalid namespace")
|
||||
};
|
||||
|
||||
let name = {
|
||||
let buffer = components[0].as_bytes();
|
||||
Value::buff_from(buffer.to_vec())
|
||||
.expect("Invalid name")
|
||||
};
|
||||
|
||||
let fqn = Value::Tuple(TupleData::from_data(vec![
|
||||
("namespace".into(), namespace),
|
||||
("name".into(), name),
|
||||
]).unwrap());
|
||||
|
||||
let owner_address = StacksChainState::parse_genesis_address(&entry.owner, mainnet);
|
||||
|
||||
let zonefile_hash = {
|
||||
if entry.zonefile_hash.len() == 0 {
|
||||
Value::buff_from(vec![]).unwrap()
|
||||
} else {
|
||||
let buffer = Hash160::from_hex(&entry.zonefile_hash)
|
||||
.expect("Invalid zonefile_hash");
|
||||
Value::buff_from(buffer.to_bytes().to_vec()).unwrap()
|
||||
}
|
||||
};
|
||||
|
||||
db.set_nft_owner(
|
||||
&bns_contract_id,
|
||||
"names",
|
||||
&fqn,
|
||||
&owner_address,
|
||||
)?;
|
||||
|
||||
let registered_at = Value::UInt(entry.registered_at.into());
|
||||
let name_props = Value::Tuple(
|
||||
TupleData::from_data(vec![
|
||||
("registered-at".into(), Value::some(registered_at).unwrap()),
|
||||
("imported-at".into(), Value::none()),
|
||||
("revoked-at".into(), Value::none()),
|
||||
("zonefile-hash".into(), zonefile_hash),
|
||||
])
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
db.insert_entry(
|
||||
&bns_contract_id,
|
||||
"name-properties",
|
||||
fqn.clone(),
|
||||
name_props,
|
||||
)?;
|
||||
|
||||
db.insert_entry(
|
||||
&bns_contract_id,
|
||||
"owner-name",
|
||||
Value::Principal(owner_address),
|
||||
fqn,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(callback) = boot_data.post_flight_callback.take() {
|
||||
callback(&mut clarity_tx);
|
||||
}
|
||||
@@ -1772,6 +1943,8 @@ pub mod test {
|
||||
first_burnchain_block_timestamp: 0,
|
||||
get_bulk_initial_lockups: None,
|
||||
get_bulk_initial_balances: None,
|
||||
get_bulk_initial_names: None,
|
||||
get_bulk_initial_namespaces: None,
|
||||
};
|
||||
|
||||
StacksChainState::open_and_exec(
|
||||
|
||||
@@ -468,6 +468,8 @@ fn main() {
|
||||
first_burnchain_block_timestamp: 0,
|
||||
get_bulk_initial_lockups: None,
|
||||
get_bulk_initial_balances: None,
|
||||
get_bulk_initial_namespaces: None,
|
||||
get_bulk_initial_names: None,
|
||||
};
|
||||
|
||||
let (mut new_chainstate, _) = StacksChainState::open_and_exec(
|
||||
|
||||
@@ -868,8 +868,9 @@ fn test_buff() {
|
||||
"(if true \"blockstack\" \"block\")",
|
||||
"(if true \"block\" \"blockstack\")",
|
||||
"(len \"blockstack\")",
|
||||
"(len 0x)",
|
||||
];
|
||||
let expected = ["(string-ascii 10)", "(string-ascii 10)", "uint"];
|
||||
let expected = ["(string-ascii 10)", "(string-ascii 10)", "uint", "uint"];
|
||||
let bad = [
|
||||
"(fold and (list true false) 2)",
|
||||
"(fold hash160 (list 1 2 3 4) 2)",
|
||||
|
||||
@@ -713,6 +713,10 @@ fn test_buff_len() {
|
||||
let test1 = "(len \"blockstack\")";
|
||||
let expected = Value::UInt(10);
|
||||
assert_eq!(expected, execute(test1).unwrap().unwrap());
|
||||
|
||||
let test2 = "(len 0x)";
|
||||
let expected = Value::UInt(0);
|
||||
assert_eq!(expected, execute(test2).unwrap().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -21,20 +21,20 @@ pub struct GenesisAccountLockup {
|
||||
|
||||
pub struct GenesisNamespace {
|
||||
pub namespace_id: String,
|
||||
pub address: String,
|
||||
pub importer: String,
|
||||
pub reveal_block: i64,
|
||||
pub ready_block: i64,
|
||||
pub buckets: String,
|
||||
pub base: String,
|
||||
pub coeff: String,
|
||||
pub nonalpha_discount: String,
|
||||
pub no_vowel_discount: String,
|
||||
pub lifetime: String,
|
||||
pub base: i64,
|
||||
pub coeff: i64,
|
||||
pub nonalpha_discount: i64,
|
||||
pub no_vowel_discount: i64,
|
||||
pub lifetime: i64,
|
||||
}
|
||||
|
||||
pub struct GenesisName {
|
||||
pub name: String,
|
||||
pub address: String,
|
||||
pub fully_qualified_name: String,
|
||||
pub owner: String,
|
||||
pub registered_at: i64,
|
||||
pub expire_block: i64,
|
||||
pub zonefile_hash: String,
|
||||
@@ -114,23 +114,23 @@ fn read_lockups(deflate_bytes: &'static [u8]) -> Box<dyn Iterator<Item = Genesis
|
||||
fn read_namespaces(deflate_bytes: &'static [u8]) -> Box<dyn Iterator<Item = GenesisNamespace>> {
|
||||
let namespaces = iter_deflated_csv(deflate_bytes).map(|cols| GenesisNamespace {
|
||||
namespace_id: cols[0].to_string(),
|
||||
address: cols[1].to_string(),
|
||||
importer: cols[1].to_string(),
|
||||
reveal_block: cols[2].parse::<i64>().unwrap(),
|
||||
ready_block: cols[3].parse::<i64>().unwrap(),
|
||||
buckets: cols[4].to_string(),
|
||||
base: cols[5].to_string(),
|
||||
coeff: cols[6].to_string(),
|
||||
nonalpha_discount: cols[7].to_string(),
|
||||
no_vowel_discount: cols[8].to_string(),
|
||||
lifetime: cols[9].to_string(),
|
||||
base: cols[5].parse::<i64>().unwrap(),
|
||||
coeff: cols[6].parse::<i64>().unwrap(),
|
||||
nonalpha_discount: cols[7].parse::<i64>().unwrap(),
|
||||
no_vowel_discount: cols[8].parse::<i64>().unwrap(),
|
||||
lifetime: cols[9].parse::<i64>().unwrap(),
|
||||
});
|
||||
return Box::new(namespaces);
|
||||
}
|
||||
|
||||
fn read_names(deflate_bytes: &'static [u8]) -> Box<dyn Iterator<Item = GenesisName>> {
|
||||
let names = iter_deflated_csv(deflate_bytes).map(|cols| GenesisName {
|
||||
name: cols[0].to_string(),
|
||||
address: cols[1].to_string(),
|
||||
fully_qualified_name: cols[0].to_string(),
|
||||
owner: cols[1].to_string(),
|
||||
registered_at: cols[2].parse::<i64>().unwrap(),
|
||||
expire_block: cols[3].parse::<i64>().unwrap(),
|
||||
zonefile_hash: cols[4].to_string(),
|
||||
|
||||
@@ -7,7 +7,7 @@ use std::net::SocketAddr;
|
||||
use std::{collections::HashSet, env};
|
||||
use std::{thread, thread::JoinHandle, time};
|
||||
|
||||
use stacks::chainstate::burn::db::sortdb::SortitionDB;
|
||||
use stacks::chainstate::{burn::db::sortdb::SortitionDB};
|
||||
use stacks::chainstate::burn::operations::{
|
||||
leader_block_commit::{RewardSetInfo, BURN_BLOCK_MINED_AT_MODULUS},
|
||||
BlockstackOperationType, LeaderBlockCommitOp, LeaderKeyRegisterOp,
|
||||
@@ -29,7 +29,7 @@ use stacks::net::{
|
||||
};
|
||||
use stacks::{
|
||||
burnchains::{Burnchain, BurnchainHeaderHash, Txid},
|
||||
chainstate::stacks::db::{ChainstateAccountBalance, ChainstateAccountLockup},
|
||||
chainstate::stacks::db::{ChainstateAccountBalance, ChainstateAccountLockup, ChainstateBNSNamespace, ChainstateBNSName},
|
||||
};
|
||||
|
||||
use stacks::chainstate::stacks::index::TrieHash;
|
||||
@@ -111,6 +111,43 @@ pub fn get_account_balances(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_namespaces(
|
||||
use_test_chainstate_data: bool,
|
||||
) -> Box<dyn Iterator<Item = ChainstateBNSNamespace>> {
|
||||
Box::new(
|
||||
stx_genesis::GenesisData::new(use_test_chainstate_data)
|
||||
.read_namespaces()
|
||||
.map(|item| ChainstateBNSNamespace {
|
||||
namespace_id: item.namespace_id,
|
||||
importer: item.importer,
|
||||
revealed_at: item.reveal_block as u64,
|
||||
launched_at: item.ready_block as u64,
|
||||
buckets: item.buckets,
|
||||
base: item.base as u64,
|
||||
coeff: item.coeff as u64,
|
||||
nonalpha_discount: item.nonalpha_discount as u64,
|
||||
no_vowel_discount: item.no_vowel_discount as u64,
|
||||
lifetime: item.lifetime as u64,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_names(
|
||||
use_test_chainstate_data: bool,
|
||||
) -> Box<dyn Iterator<Item = ChainstateBNSName>> {
|
||||
Box::new(
|
||||
stx_genesis::GenesisData::new(use_test_chainstate_data)
|
||||
.read_names()
|
||||
.map(|item| ChainstateBNSName {
|
||||
fully_qualified_name: item.fully_qualified_name,
|
||||
owner: item.owner,
|
||||
registered_at: item.registered_at as u64,
|
||||
expired_at: item.expire_block as u64,
|
||||
zonefile_hash: item.zonefile_hash,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
fn spawn_peer(
|
||||
mut this: PeerNetwork,
|
||||
p2p_sock: &SocketAddr,
|
||||
@@ -218,6 +255,13 @@ impl Node {
|
||||
get_bulk_initial_balances: Some(Box::new(move || {
|
||||
get_account_balances(use_test_genesis_data)
|
||||
})),
|
||||
get_bulk_initial_namespaces: Some(Box::new(move || {
|
||||
get_namespaces(use_test_genesis_data)
|
||||
})),
|
||||
get_bulk_initial_names: Some(Box::new(move || {
|
||||
get_names(use_test_genesis_data)
|
||||
})),
|
||||
|
||||
};
|
||||
|
||||
let chain_state_result = StacksChainState::open_and_exec(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
genesis_data::USE_TEST_GENESIS_CHAINSTATE,
|
||||
neon_node,
|
||||
node::{get_account_balances, get_account_lockups},
|
||||
node::{get_account_balances, get_account_lockups, get_namespaces, get_names},
|
||||
BitcoinRegtestController, BurnchainController, Config, EventDispatcher, Keychain,
|
||||
NeonGenesisNode,
|
||||
};
|
||||
@@ -206,6 +206,13 @@ impl RunLoop {
|
||||
get_bulk_initial_balances: Some(Box::new(|| {
|
||||
get_account_balances(USE_TEST_GENESIS_CHAINSTATE)
|
||||
})),
|
||||
get_bulk_initial_namespaces: Some(Box::new(|| {
|
||||
get_namespaces(USE_TEST_GENESIS_CHAINSTATE)
|
||||
})),
|
||||
get_bulk_initial_names: Some(Box::new(|| {
|
||||
get_names(USE_TEST_GENESIS_CHAINSTATE)
|
||||
})),
|
||||
|
||||
};
|
||||
|
||||
let (chain_state_db, receipts) = StacksChainState::open_and_exec(
|
||||
|
||||
@@ -1889,7 +1889,7 @@ fn atlas_integration_test() {
|
||||
}
|
||||
|
||||
// (define-public (name-import (namespace (buff 20))
|
||||
// (name (buff 32))
|
||||
// (name (buff 48))
|
||||
// (zonefile-hash (buff 20)))
|
||||
let zonefile_hex = "facade00";
|
||||
let hashed_zonefile = Hash160::from_data(&hex_bytes(zonefile_hex).unwrap());
|
||||
|
||||
Reference in New Issue
Block a user