mirror of https://github.com/lukechilds/docs.git
Patrick Gray
4 years ago
committed by
Patrick Gray
8 changed files with 0 additions and 1093 deletions
@ -1,178 +0,0 @@ |
|||
--- |
|||
title: How Atlas works |
|||
description: Atlas was designed to overcome the structural weaknesses inherent to all distributed hash tables. |
|||
--- |
|||
|
|||
## Introduction |
|||
|
|||
Atlas was designed to overcome the structural weaknesses inherent to all |
|||
distributed hash tables. In particular, it uses an unstructured peer network to |
|||
maximize resilience against network link failure, and it uses the underlying |
|||
blockchain (through BNS) to rate-limit chunk announcements. |
|||
|
|||
## Peer Selection |
|||
|
|||
Atlas peers self-organize into an unstructured peer-to-peer network. |
|||
The Atlas peer network is a [random K-regular |
|||
graph](https://en.wikipedia.org/wiki/Random_regular_graph). Each node maintains |
|||
_K_ neighbors chosen at random from the set of Atlas peers. |
|||
|
|||
Atlas nodes select peers by carrying out an unbiased random walk of the peer |
|||
graph. When "visiting" a node _N_, it will ask for _N_'s neighbors and then |
|||
"step" to one of them with a probability dependent on _N_'s out-degree and the |
|||
neighbor's in-degree. |
|||
|
|||
The sampling algorithm is based on the Metropolis-Hastings (MH) random graph walk |
|||
algorithm, but with a couple key differences. In particular, the algorithm |
|||
attempts to calculate an unbiased peer graph sample that accounts for the fact |
|||
that most nodes will be short-lived or unreliable, while a few persistent nodes |
|||
will remain online for long periods of time. The sampling algorithm accounts |
|||
for this with the following tweaks: |
|||
|
|||
- If the neighbors of the visited node _N_ are all unresponsive, the random |
|||
walk resets to a randomly chosen known neighbor. There is no back-tracking on |
|||
the peer graph in this case. |
|||
|
|||
- The transition probability from _N_ to a live neighbor is _NOT_ `min(1, degree(neighbor)/degree(N))` like it is in the vanilla MH algorithm. Instead, |
|||
the transition probability discourages backtracking to the previous neighbor _N_prev_, |
|||
but in a way that still guarantees that the sampling will remain unbiased. |
|||
|
|||
- A peer does not report its entire neighbor set when queried, |
|||
but only reports a random subset of peers that have met a minimum health threshold. |
|||
|
|||
- A new neighbor is only selected if it belongs to the same [BNS |
|||
fork-set](/naming-services/overview#bns-forks) (for example, it reports |
|||
as having a recent valid consensus hash). |
|||
|
|||
The algorithm was adapted from the work from [Lee, Xu, and |
|||
Eun](https://arxiv.org/pdf/1204.4140.pdf) in the proceedings of |
|||
ACM SIGMETRICS 2012. |
|||
|
|||
## Comparison to DHTs |
|||
|
|||
The reason Atlas uses an unstructured random peer network |
|||
instead of a [distributed hash table](https://en.wikipedia.org/wiki/Distributed_hash_table) |
|||
(DHT) is that DHTs are susceptible to Sybil attacks. An adaptive adversary can |
|||
insert malicious nodes into the DHT in order to stop victims from |
|||
resolving chunks or finding honest neighbors. |
|||
|
|||
### Chunk Censorship |
|||
|
|||
In a DHT, an attacker can censor a chunk by inserting nodes into the peers' routing tables |
|||
such that the attacker takes control over all of the chunk's hash buckets. |
|||
It can do so at any point in time after the chunk was first stored, |
|||
because only the peers who maintain the chunk's hash bucket have to store it. |
|||
This is a _fundamental_ problem with structured overlay networks |
|||
that perform request routing based on content hash---they give the attacker |
|||
insight as to the paths the queries take through the peer graph, and thus |
|||
reduce the number of paths the attacker must disrupt in order to censor the |
|||
chunk. |
|||
|
|||
Atlas uses an unstructured overlay network combined with a 100% chunk |
|||
replication strategy in order to maximize |
|||
the amount of work an adversary has to do to censor a chunk. |
|||
In Atlas, all peers replicate a chunk, and the paths the chunk take through the |
|||
network are _independent_ of the content and _randomized_ by the software |
|||
(so the paths cannot be predicted in advance). The attacker's only |
|||
recourse is to quickly identify the nodes that can serve the chunk and partition them from |
|||
the rest of the network in order to carry out a censorship attack. |
|||
This requires them to have visibility into the vast majority of network links in |
|||
the Atlas network (which is extremely difficult to do, because in practice Atlas |
|||
peers maintain knowledge of up to 65536 neighbors and only report 10 random peers |
|||
when asked). |
|||
|
|||
### Neighbor Censorship |
|||
|
|||
Another problem with DHTs is that their overlay |
|||
network structure is determined by preferential attachment. Not every peer that |
|||
contacts a given DHT node has an equal chance of becoming its neighbor. |
|||
The node will instead rank a set of peers as being more or less ideal |
|||
for being neighbors. In DHTs, the degree of preference a node exhibits to |
|||
another node is usually a function of the node's self-given node identifier |
|||
(for example a node might want to select neighbors based on proximity in the key |
|||
space). |
|||
|
|||
The preferential attachment property means that an adaptive adversary can game the node's |
|||
neighbor selection algorithm by inserting malicious nodes that do not |
|||
forward routing or lookup requests. The attacker does not even have to eclipse |
|||
the victim node---the victim node will simply prefer to talk to the attacker's unhelpful nodes |
|||
instead of helpful honest nodes. In doing so, the attacker can prevent honest peers from discovering each |
|||
other and each other's chunks. |
|||
|
|||
Atlas's neighbor selection strategy does not exhibit preferential attachment |
|||
based on any self-reported node properties. A |
|||
node is selected as a neighbor only if it is reached through an unbiased random graph |
|||
walk, and if it responds to queries correctly. |
|||
In doing so, an attacker is forced to completely eclipse a set of nodes |
|||
in order to cut them off from the rest of the network. |
|||
|
|||
## Chunk Propagation |
|||
|
|||
Atlas nodes maintain an _inventory_ of chunks that are known to exist. Each |
|||
node independently calculates the chunk inventory from its BNS database. |
|||
Because the history of name operations in BNS is linearized, each node can |
|||
construct a linearized sub-history of name operations that can set chunk |
|||
hashes as their name state. This gives them a linearized sequence of chunks, |
|||
and every Atlas peer will independently arrive at the same sequence by reading |
|||
the same blockchain. |
|||
|
|||
Atlas peers keep track of which chunks are present and which are absent. They |
|||
each construct an _inventory vector_ of chunks _V_ such that _V[i]_ is set to 1 |
|||
if the node has the chunk whose hash is in the *i*th position in the chunk |
|||
sequence (and set to 0 if it is absent). |
|||
|
|||
Atlas peers exchange their inventory vectors with their neighbors in order to |
|||
find out which chunks they each have. Atlas nodes download chunks from |
|||
neighbors in rarest-first order in order to prioritize data replication for the |
|||
chunks that are currently most at-risk for disappearing due to node failure. |
|||
|
|||
``` |
|||
Name operation | chunk hashes | chunk data | Inventory |
|||
history | as name state | | vector |
|||
|
|||
+-------------------+ |
|||
| NAME_PREORDER | |
|||
+-------------------+----------------+ |
|||
| NAME_REGISTRATION | chunk hash | "0123abcde..." 1 |
|||
+-------------------+----------------+ |
|||
| NAME_UPDATE | chunk hash | (null) 0 |
|||
+-------------------+----------------+ |
|||
| NAME_TRANSFER | |
|||
+-------------------+ |
|||
| NAME_PREORDER | |
|||
+-------------------+----------------+ |
|||
| NAME_IMPORT | chunk hash | "4567fabcd..." 1 |
|||
+-------------------+----------------+ |
|||
| NAME_TRANSFER | |
|||
+-------------------| |
|||
. . . |
|||
|
|||
|
|||
Figure 2: Relationship between Atlas node chunk inventory and BNS name state. |
|||
Some name operations announce name state in the blockchain, which Atlas |
|||
interprets as a chunk hash. The Atlas node builds up a vector of which chunks |
|||
it has and which ones it does not, and announces it to other Atlas peers so |
|||
they can fetch chunks they are missing. In this example, the node's |
|||
inventory vector is [1, 0, 1], since the 0th and 2nd chunks are present |
|||
but the 1st chunk is missing. |
|||
``` |
|||
|
|||
## Querying Chunk Inventories |
|||
|
|||
Developers can query a node's inventory vector as follows: |
|||
|
|||
```py |
|||
>>> import blockstack |
|||
>>> result = blockstack.lib.client.get_zonefile_inventory("https://node.blockstack.org:6263", 0, 524288) |
|||
>>> print len(result['inv']) |
|||
11278 |
|||
>>> |
|||
``` |
|||
|
|||
The variable `result['inv']` here is a big-endian bit vector, where the *i*th |
|||
bit is set to 1 if the *i*th chunk in the chunk sequence is present. The bit at |
|||
`i=0` (the earliest chunk) refers to the leftmost bit. |
|||
|
|||
A sample program that inspects a set of Atlas nodes' inventory vectors and determines |
|||
which ones are missing which chunks can be found |
|||
[here](https://github.com/blockstack/atlas/blob/master/atlas/atlas-test). |
@ -1,121 +0,0 @@ |
|||
--- |
|||
title: Overview of the Atlas network |
|||
description: This document describes the Atlas network, a peer-to-peer content-addressed storage system whose chunks' hashes are announced on a public blockchain. |
|||
--- |
|||
|
|||
## Introduction |
|||
|
|||
This document describes the Atlas network, a peer-to-peer content-addressed |
|||
storage system whose chunks' hashes are announced on a public blockchain. Atlas |
|||
allows users and developers to **permanently store** chunks of data that are |
|||
**replicated across every peer.** As long as at least one Atlas peer is online, |
|||
all chunks are available to clients. |
|||
|
|||
This document is aimed at developers and technical users. |
|||
|
|||
The reader of this document is expected to be familiar with the [Blockchain Naming Service (BNS)](/build-apps/references/bns), |
|||
as well as Stacks's storage system [Gaia](https://github.com/blockstack/gaia). We advise the reader |
|||
to familiarize themselves with both systems before approaching this document. |
|||
|
|||
## Architecture |
|||
|
|||
Atlas is designed to integrate with BNS in order to allow users to |
|||
store name state off-chain, encoded as a DNS zone file. |
|||
The common use-cases in Stacks are: |
|||
|
|||
- Storing a name's routing information for its owners' [Gaia](https://github.com/blockstack/gaia) |
|||
datastores. |
|||
- Storing BNS subdomain transactions and associated state. |
|||
|
|||
Atlas is a middleware system in Stacks. Most developers do not |
|||
interact with it directly. BNS clients like the |
|||
[Blockstack Browser](https://github.com/blockstack/blockstack-browser) |
|||
automatically generate zone files for the names they register, and automatically |
|||
propagate them to the Atlas network. BNS API endpoints, including our |
|||
[public endpoint](https://core.blockstack.org) and the |
|||
[blockstack.js](https://github.com/blockstack/blockstack.js) library, |
|||
will automatically fetch zone files from Atlas when they need to look |
|||
up data in Gaia (such as profiles and app data). |
|||
|
|||
``` |
|||
+--------------+ +---------------+ +----------------+ |
|||
clients |Authenticator | | Stacks.js | | BNS API module | |
|||
+--------------+ +---------------+ +----------------+ |
|||
^ ^ ^ ^ ^ ^ |
|||
| | | | | | |
|||
| | | | | | |
|||
V | V | V | |
|||
+----------+ | +----------+ | +----------+ | |
|||
Gaia | Gaia hub | | | Gaia hub | | | Gaia hub | | |
|||
+----------+ | +----------+ | +----------+ | |
|||
| | | |
|||
| | | |
|||
V V V |
|||
+---------------------------------------------------------------+ |
|||
Atlas | Atlas Peer Network | |
|||
+----------+------+----------+-----+----------+------+----------+ |
|||
BNS | BNS node | | BNS node | | BNS node | | BNS node | |
|||
+----------+ +----------+ +----------+ +----------+ |
|||
^ ^ ^ ^ |
|||
| (indexing | | | |
|||
| blockchain) | | | |
|||
+---------------------------------------------------------------+ |
|||
Blockchain | Blockchain Peer Network | |
|||
+---------------------------------------------------------------+ |
|||
|
|||
|
|||
Figure 1: Location of Atlas in the Stacks architecture Each BNS node |
|||
implements an Atlas peer An Atlas peer treats a name state value in BNS as |
|||
the hash of a DNS zone file Atlas peers exchange zone files with one another |
|||
until they each have a full replica of all known zone files Clients can look |
|||
up zone files for names using the name's stat value as a zone file hash Clients |
|||
can broadcast zone files to the network if they match a previously announced |
|||
hash In practice, zone files store URLs to a name owner's Gaia hubs, thereby |
|||
allowing Stacks apps to read and write data in Gaia. |
|||
``` |
|||
|
|||
Nevertheless, Atlas is a general-purpose content-addressed storage |
|||
system that advanced developers can use to **host data in an immutable |
|||
and durable manner.** Beyond its default use-case in Stacks, |
|||
Atlas is ideal for tasks like: |
|||
|
|||
- Announcing PGP public keys under a human-readable name |
|||
- Storing package hashes for a software release |
|||
- Securely deploying shell scripts to remote VMs |
|||
- Binding human-readable names to Tor .onion addresses |
|||
([example](https://github.com/blockstack-packages/blockstack-tor)) |
|||
|
|||
## Motivation |
|||
|
|||
Atlas was designed to augment BNS. BNS allows each name to store a small |
|||
amount of state---on the order of 20 bytes. The size is so small because the |
|||
state must be recorded to a public blockchain, where the cost per byte is |
|||
high and the blockchain protocol limits the size of transactions. |
|||
|
|||
To compensate for this, we developed an off-chain storage system allows BNS |
|||
names to bind and store a large amount of state to each name in a way that |
|||
_preserves the security properties of having written that state to the |
|||
blockchain_. Instead of storing 20 bytes of data on the blockchain, a BNS name |
|||
owner would store the _cryptographic hash_ of its state, and then store the actual state |
|||
Atlas. This decouples the name's state size from the blockchain. |
|||
|
|||
The reference implementation of Atlas currently allows up to 40kb of state to be |
|||
bound to a BNS name, instead of a measly 20 bytes. The 40kb of data is |
|||
replicated to each BNS node, where it is stored forever. |
|||
|
|||
## Feature Comparison |
|||
|
|||
Atlas is not the only peer-to-peer content-addressible chunk store in existence. The following |
|||
feature table describes Atlas in relation to other popular chunk stores. |
|||
|
|||
| **Features** | Atlas | BitTorrent | [DAT](https://datproject.org/) | [IPFS](https://ipfs.io) | [Swarm](https://github.com/ethersphere/swarm) | |
|||
| ------------------------------- | ----- | ---------- | ------------------------------ | ----------------------- | --------------------------------------------- | |
|||
| Each peer stores all chunks | X | X | | | | |
|||
| Replicas are permanent [^1] | X | X | X | | | |
|||
| Replicas are free | | X | X | X | | |
|||
| Sybil-resistant chunk discovery | X | X | | | X | |
|||
| Sybil-resistant peer discovery | X | | | | | |
|||
| Fixed chunk size | X | | X | X | X | |
|||
|
|||
[^1] Here, "permanent" means that once a peer has data, they will never evict it |
|||
as part of the protocol. |
@ -1,119 +0,0 @@ |
|||
--- |
|||
title: How to use the Atlas network |
|||
description: This section teaches you how to use the Atlas network. |
|||
--- |
|||
|
|||
## The API |
|||
|
|||
While the Stacks software stack expects that Atlas-hosted data is made up of |
|||
DNS zone files, Atlas itself does not enforce this (nor does it care about the |
|||
format of its chunks). It is designed as a general-purpose chunk store. |
|||
Nevertheless, the ubiquitous use of Atlas to store data as DNS zone files has |
|||
had an influence on its API design---fields and method names frequently allude |
|||
to zone files and zone file hashes. This is intentional. |
|||
|
|||
The [public BNS API endpoint](https://core.blockstack.org) does not support |
|||
resolving Atlas chunks that do not encode Gaia routing information or subdomain |
|||
information. To directly interact with Atlas, developers will need to install |
|||
[Stacks Node](https://github.com/blockstack/blockstack-core) and use its |
|||
Python client libraries for these examples. |
|||
|
|||
## Looking up Chunks |
|||
|
|||
All Atlas chunks are addressed by the RIPEMD160 hash of the SHA256 hash of the |
|||
chunk data. A client can query up to 100 chunks in one RPC call. |
|||
|
|||
A client can look up a chunk with the `get_zonefiles()` method. If successful, |
|||
the returned payload will be a `dict` with a `zonefiles` key that maps the chunk |
|||
hashes to their respective data. |
|||
|
|||
```py |
|||
>>> import blockstack |
|||
>>> data = blockstack.lib.client.get_zonefiles('https://node.blockstack.org:6263', ['1b89a685f4c4ea245ce9433d0b29166c22175ab4']) |
|||
>>> print data['zonefiles']['1b89a685f4c4ea245ce9433d0b29166c22175ab4'] |
|||
$ORIGIN duckduckgo_tor.id |
|||
$TTL 3600 |
|||
tor TXT "3g2upl4pq6kufc4m.onion" |
|||
|
|||
>>> |
|||
``` |
|||
|
|||
(This particular chunk happens to be associated with the BNS name |
|||
`duckduckgo_tor.id`). |
|||
|
|||
## Adding a New Chunk |
|||
|
|||
The only way to add a chunk to Atlas is to do so through an on-chain name in |
|||
BNS. Adding a new chunk is a two-step process: |
|||
|
|||
- The name owner announces the chunk hash as a name's state |
|||
via a `NAME_REGISTRATION`, `NAME_UPDATE`, `NAME_RENEWAL`, or `NAME_IMPORT` transaction. |
|||
- Once the transaction is confirmed and processed by BNS, the name owner |
|||
broadcasts the matching zone file. |
|||
|
|||
Setting a name's state to be the hash of a chunk is beyond the scope of this |
|||
document, since it needs to be done through a BNS client. |
|||
See the relevant documentation for |
|||
[blockstack.js](https://github.com/blockstack/blockstack.js) and the [Blockstack |
|||
Browser](https://github.com/blockstack/blockstack-browser) for doing this. |
|||
|
|||
Once the name operation is confirmed, you can announce the data to the |
|||
Atlas network. You can do so with the Python client as follows: |
|||
|
|||
```py |
|||
>>> import blockstack |
|||
>>> import base64 |
|||
>>> data = "..." # this is the chunk data you will announce |
|||
>>> data_b64 = base64.b64encode(data) |
|||
>>> result = blockstack.lib.client.put_zonefiles('https://node.blockstack.org:6263', [data_b64]) |
|||
>>> assert result['saved'][0] == 1 |
|||
>>> |
|||
``` |
|||
|
|||
At most five chunks can be announced in one RPC call. |
|||
Note that the data must be base64-encoded before it can be announced. |
|||
|
|||
When the `put_zonefiles()` method succeeds, it returns a `dict` with a list |
|||
under the `saved` key. Here, `result['saved'][i]` will be 1 if the `i`th |
|||
chunk given to `put_zonefiles()` was saved by the node, and 0 if not. |
|||
The node will not save a chunk if it is too big, or if it has not yet processed |
|||
the name operation that contained the chunk's hash. |
|||
|
|||
The `put_zonefiles()` method is idempotent. |
|||
|
|||
## Propagating Chunks |
|||
|
|||
Atlas peers will each store a copy of the chunks you announce. In the |
|||
background, they will asynchronously announce to one another which chunks they |
|||
have available, and replicate them to one another in a rarest-first order (much |
|||
like how BitTorrent works). Eventually, every Atlas peer will receive the |
|||
chunk. |
|||
|
|||
However, developers can accelerate this process by eagerly propagating chunks. |
|||
To do so, they can ask an Atlas peer for its immediate neighbors in the Atlas |
|||
peer graph, and replicate the chunk to each of them as well. |
|||
|
|||
For example, this code will replicate the chunk to not only |
|||
`https://node.blockstack.org:6263`, but also to its immediate neighbors. |
|||
|
|||
```py |
|||
>>> import blockstack |
|||
>>> import base64 |
|||
>>> data = "..." # this is the chunk you will replicate widely |
|||
>>> data_b64 = base64.b64encode(data) |
|||
>>> |
|||
>>> result = blockstack.lib.client.get_atlas_peers('https://node.blockstack.org:6263') |
|||
>>> neighbors = result['peers'] |
|||
>>> print ", ".join(neighbors) |
|||
13.65.207.163:6264, 52.225.128.191:6264, node.blockstack.org:6264, 23.102.162.7:6264, 52.167.230.235:6264, 23.102.162.124:6264, 52.151.59.26:6264, 13.92.134.106:6264 |
|||
>>> |
|||
>>> for neighbor in neighbors: |
|||
.. result = blockstack.lib.client.put_zonefiles(neighbor, [data_b64]) |
|||
... assert result['saved'][0] == 1 |
|||
... |
|||
>>> |
|||
``` |
|||
|
|||
This is not strictly necessary, but it does help accelerate chunk replication |
|||
and makes it less likely that a chunk will get lost due to individual node |
|||
failures. |
@ -1,62 +0,0 @@ |
|||
--- |
|||
title: Best practices |
|||
description: Helpful tips for getting a core node up and running. |
|||
--- |
|||
|
|||
## Hardware and OS requirements |
|||
|
|||
- A 64-bit CPU running at at least 1 GHz is _highly_ recommended (but not strictly required) |
|||
- You will need ~250 MB RAM and ~10 GB disk free. Do **not** attempt to use a network-attached disk for this. |
|||
- You should have at least 30,000 inodes free in your filesystem. Unless you are using a very small VM image, you almost certainly have enough (you can check with `df -i`). |
|||
- TCP port 6264 should be open and support bidirectional traffic. If you want to use SSL, then port 6263 should be open. |
|||
- A reliable Internet connection of DSL-like quality or higher |
|||
|
|||
## Deployment |
|||
|
|||
### The Easy Way |
|||
|
|||
- Install from `pip`, source code, or Docker |
|||
- Run `blockstack-core fast_sync` |
|||
- Run `blockstack-core start` |
|||
|
|||
### The Less Easy Way |
|||
|
|||
- Install from `pip`, source code, or Docker |
|||
- Run `blockstack-core start` |
|||
- Wait a few days |
|||
|
|||
#### Best Practices for the Less Easy Way |
|||
|
|||
- Take a `blockstack-server.snapshots` database from a known-good node and pass `--expected_snapshots=/path/to/blockstack-server.snapshots`. This will force your bootstrapping node to verify that it reaches the same sequence of consensus hashes as it bootstraps (that is, your node will detect any divergence from Blockstack's name history and abort early, instead of wasting your time). |
|||
- Make sure you're in a position to leave the node online at 100% CPU use for the duration of its bootstrapping period |
|||
|
|||
### The Hard Way |
|||
|
|||
- Install `bitcoind` (version 0.16.x is recommended for now) |
|||
- Start `bitcoind` as `bitcoind -daemon -txindex=1` |
|||
- Wait for `bitcoind` to download the entire blockchain. This can take between 1 hour and 1 day. |
|||
- Install `blockstack-core` from source, `pip`, or Docker |
|||
- Run `blockstack-core configure` and enter your `bitcoind` node's IP address, port, RPC username, and RPC password when prompted |
|||
- Run `blockstack-core start` |
|||
- Wait a few days |
|||
|
|||
#### Best Practices for the Hard Way |
|||
|
|||
- You're going to need ~500 GB of space for the Bitcoin blockchain state |
|||
- You can safely store its chain state on a network-attached disk, if you're doing this in a cloud-hosted environment |
|||
- Your `bitcoind` host will need TCP:8332-8333 open for bidirectional traffic |
|||
|
|||
## Troubleshooting |
|||
|
|||
### The node stops responding to TCP:6264 |
|||
|
|||
- Check `dmesg` for TCP SYN flooding. The solution here is to kill and restart the node. |
|||
- To mitigate, install a rate-limiting proxy HTTP server in front of the node. We have a sample config for `nginx` [here](https://github.com/blockstack/atlas/blob/master/public_fleet/node/default). |
|||
|
|||
### No other Stacks nodes contact my node |
|||
|
|||
- Verify that your IP address is publicly routable, and that peers can communicate on TCP:6264 |
|||
|
|||
### People are attacking my Bitcoin node |
|||
|
|||
- Stick an `nginx` reverse proxy in front of your `bitcoind` node, and use our [nginx](https://github.com/blockstack/atlas/tree/master/public_fleet/bitcoind) scripts to limit API access to only the JSON-RPC methods Stacks actually needs. Better yet, do what we do---build a statically linked `bitcoind` binary from source that simply omits all of the RPC methods except the ones listed in the linked config file. |
@ -1,44 +0,0 @@ |
|||
--- |
|||
title: Installing Memcached |
|||
description: Learn how to install Memcached to improve performance of a local Stacks API instance. |
|||
--- |
|||
|
|||
The Stacks API optionally uses memcached and pylibmc for scaling read-only |
|||
calls. If you want to enable this functionality then you should have memcached |
|||
running locally. |
|||
|
|||
### Memcached on Debian & Ubuntu: |
|||
|
|||
```bash |
|||
sudo apt-get install -y python-dev libmemcached-dev zlib1g-dev |
|||
pip install pylibmc |
|||
``` |
|||
|
|||
### Memcached on macOS: |
|||
|
|||
Easiest way to install memcached on macOS is by using [Homebrew](https://brew.sh/). |
|||
|
|||
After installing Homebrew: |
|||
|
|||
```bash |
|||
brew install memcached |
|||
brew install libmemcached |
|||
pip install pylibmc --install-option="--with-libmemcached=/usr/local/Cellar/libmemcached/1.0.18_1/" |
|||
``` |
|||
|
|||
After installing, you can start memcached and check if it's running properly: |
|||
|
|||
```bash |
|||
memcached -d |
|||
echo stats | nc localhost 11211 |
|||
``` |
|||
|
|||
### Memcached on Heroku |
|||
|
|||
To deploy on Heroku: |
|||
|
|||
```bash |
|||
heroku create |
|||
heroku addons:add memcachedcloud |
|||
git push heroku master |
|||
``` |
@ -1,10 +0,0 @@ |
|||
--- |
|||
title: Stacks 1.0 Info |
|||
description: Get familiar with the old Stacks 1.0 architecture |
|||
--- |
|||
|
|||
## Information |
|||
|
|||
Stacks 1.0 is an older blockchain architecture Stacks. |
|||
|
|||
!> Stacks 1.0 architecture is not compatible with Stacks 2.0. The information in this chapter is in reference to **deprecated** implementation details. |
@ -1,550 +0,0 @@ |
|||
--- |
|||
title: Bitcoin wire format |
|||
description: Learn about the format of transactions used for name operations in the Stacks network. |
|||
--- |
|||
|
|||
## Introduction |
|||
|
|||
This page is for organizations who want to be able to create and send name operation transactions to the blockchains Stacks supports. |
|||
It describes the transaction formats for the Bitcoin blockchain. |
|||
|
|||
## Transaction format |
|||
|
|||
Each Bitcoin transaction for Stacks contains signatures from two sets of keys: the name owner, and the payer. The owner `scriptSig` and `scriptPubKey` fields are generated from the keys that own the given name. The payer `scriptSig` and `scriptPubKey` fields are used to _subsidize_ the operation. The owner keys do not pay for any operations; the owner keys only control the minimum amount of BTC required to make the transaction standard. The payer keys only pay for the transaction's fees, and (when required) they pay the name fee. |
|||
|
|||
This construction is meant to allow the payer to be wholly separate from the owner. The principal that owns the name can fund their own transactions, or they can create a signed transaction that carries out the desired operation and request some other principal (for example a parent organization) to actually pay for and broadcast the transaction. |
|||
|
|||
The general transaction layout is as follows: |
|||
|
|||
| **Inputs** | **Outputs** | |
|||
| ------------------------ | ------------------------- | |
|||
| Owner scriptSig (1) | `OP_RETURN <payload>` (2) | |
|||
| Payment scriptSig | Owner scriptPubKey (3) | |
|||
| Payment scriptSig... (4) | |
|||
| ... (4) | ... (5) | |
|||
|
|||
(1) The owner `scriptSig` is _always_ the first input. |
|||
(2) The `OP_RETURN` script that describes the name operation is _always_ the first output. |
|||
(3) The owner `scriptPubKey` is _always_ the second output. |
|||
(4) The payer can use as many payment inputs as they like. |
|||
(5) At most one output will be the "change" `scriptPubKey` for the payer. |
|||
Different operations require different outputs. |
|||
|
|||
## Payload Format |
|||
|
|||
Each Stacks transaction in Bitcoin describes the name operation within an `OP_RETURN` output. It encodes name ownership, name fees, and payments as `scriptPubKey` outputs. The specific operations are described below. |
|||
|
|||
Each `OP_RETURN` payload _always_ starts with the two-byte string `id` (called the "magic" bytes in this document), followed by a one-byte `op` that describes the operation. |
|||
|
|||
### NAME_PREORDER |
|||
|
|||
Op: `?` |
|||
|
|||
Description: This transaction commits to the _hash_ of a name. It is the first |
|||
transaction of two transactions that must be sent to register a name in BNS. |
|||
|
|||
Example: [`6730ae09574d5935ffabe3dd63a9341ea54fafae62fde36c27738e9ee9c4e889`](https://www.blocktrail.com/BTC/tx/6730ae09574d5935ffabe3dd63a9341ea54fafae62fde36c27738e9ee9c4e889) |
|||
|
|||
`OP_RETURN` wire format: |
|||
|
|||
``` |
|||
0 2 3 23 39 |
|||
|-----|--|--------------------------------------------------|--------------| |
|||
magic op hash_name(name.ns_id,script_pubkey,register_addr) consensus hash |
|||
``` |
|||
|
|||
Inputs: |
|||
|
|||
- Payment `scriptSig`'s |
|||
|
|||
Outputs: |
|||
|
|||
- `OP_RETURN` payload |
|||
- Payment `scriptPubkey` script for change |
|||
- `p2pkh` `scriptPubkey` to the burn address (0x00000000000000000000000000000000000000) |
|||
|
|||
Notes: |
|||
|
|||
- `register_addr` is a base58check-encoded `ripemd160(sha256(pubkey))` (that is, an address). This address **must not** have been used before in the underlying blockchain. |
|||
- `script_pubkey` is either a `p2pkh` or `p2sh` compiled Bitcoin script for the payer's address. |
|||
|
|||
### NAME_REGISTRATION |
|||
|
|||
Op: `:` |
|||
|
|||
Description: This transaction reveals the name whose hash was announced by a |
|||
previous `NAME_PREORDER`. It is the second of two transactions that must be |
|||
sent to register a name in BNS. |
|||
|
|||
Example: [`55b8b42fc3e3d23cbc0f07d38edae6a451dfc512b770fd7903725f9e465b2925`](https://www.blocktrail.com/BTC/tx/55b8b42fc3e3d23cbc0f07d38edae6a451dfc512b770fd7903725f9e465b2925) |
|||
|
|||
`OP_RETURN` wire format (2 variations allowed): |
|||
|
|||
Variation 1: |
|||
|
|||
``` |
|||
0 2 3 39 |
|||
|----|--|-----------------------------| |
|||
magic op name.ns_id (37 bytes) |
|||
``` |
|||
|
|||
Variation 2: |
|||
|
|||
``` |
|||
0 2 3 39 59 |
|||
|----|--|----------------------------------|-------------------| |
|||
magic op name.ns_id (37 bytes, 0-padded) value |
|||
``` |
|||
|
|||
Inputs: |
|||
|
|||
- Payer `scriptSig`'s |
|||
|
|||
Outputs: |
|||
|
|||
- `OP_RETURN` payload |
|||
- `scriptPubkey` for the owner's address |
|||
- `scriptPubkey` for the payer's change |
|||
|
|||
Notes: |
|||
|
|||
- Variation 1 simply registers the name. Variation 2 will register the name and |
|||
set a name value simultaneously. This is used in practice to set a zone file |
|||
hash for a name without the extra `NAME_UPDATE` transaction. |
|||
- Both variations are supported. Variation 1 was designed for the time when |
|||
Bitcoin only supported 40-byte `OP_RETURN` outputs. |
|||
|
|||
### NAME_RENEWAL |
|||
|
|||
Op: `:` |
|||
|
|||
Description: This transaction renews a name in BNS. The name must still be |
|||
registered and not expired, and owned by the transaction sender. |
|||
|
|||
Example: [`e543211b18e5d29fd3de7c0242cb017115f6a22ad5c6d51cf39e2b87447b7e65`](https://www.blocktrail.com/BTC/tx/e543211b18e5d29fd3de7c0242cb017115f6a22ad5c6d51cf39e2b87447b7e65) |
|||
|
|||
`OP_RETURN` wire format (2 variations allowed): |
|||
|
|||
Variation 1: |
|||
|
|||
``` |
|||
0 2 3 39 |
|||
|----|--|-----------------------------| |
|||
magic op name.ns_id (37 bytes) |
|||
``` |
|||
|
|||
Variation 2: |
|||
|
|||
``` |
|||
0 2 3 39 59 |
|||
|----|--|----------------------------------|-------------------| |
|||
magic op name.ns_id (37 bytes, 0-padded) value |
|||
``` |
|||
|
|||
Inputs: |
|||
|
|||
- Payer `scriptSig`'s |
|||
|
|||
Outputs: |
|||
|
|||
- `OP_RETURN` payload |
|||
- `scriptPubkey` for the owner's addess. This can be a different address than |
|||
the current name owner (in which case, the name is renewed and transferred). |
|||
- `scriptPubkey` for the payer's change |
|||
- `scriptPubkey` for the burn address (to pay the name cost) |
|||
|
|||
Notes: |
|||
|
|||
- This transaction is identical to a `NAME_REGISTRATION`, except for the presence of the fourth output that pays for the name cost (to the burn address). |
|||
- Variation 1 simply renews the name. Variation 2 will both renew the name and |
|||
set a new name value (in practice, the hash of a new zone file). |
|||
- Both variations are supported. Variation 1 was designed for the time when |
|||
Bitcoin only supported 40-byte `OP_RETURN` outputs. |
|||
- This operation can be used to transfer a name to a new address by setting the |
|||
second output (the first `scriptPubkey`) to be the `scriptPubkey` of the new |
|||
owner key. |
|||
|
|||
### NAME_UPDATE |
|||
|
|||
Op: `+` |
|||
|
|||
Description: This transaction sets the name state for a name to the given |
|||
`value`. In practice, this is used to announce new DNS zone file hashes to the [Atlas |
|||
network](/understand-stacks/atlas-overview). |
|||
|
|||
Example: [`e2029990fa75e9fc642f149dad196ac6b64b9c4a6db254f23a580b7508fc34d7`](https://www.blocktrail.com/BTC/tx/e2029990fa75e9fc642f149dad196ac6b64b9c4a6db254f23a580b7508fc34d7) |
|||
|
|||
`OP_RETURN` wire format: |
|||
|
|||
``` |
|||
0 2 3 19 39 |
|||
|-----|--|-----------------------------------|-----------------------| |
|||
magic op hash128(name.ns_id,consensus hash) zone file hash |
|||
``` |
|||
|
|||
Note that `hash128(name.ns_id, consensus hash)` is the first 16 bytes of a SHA256 hash over the name concatenated to the hexadecimal string of the consensus hash (not the bytes corresponding to that hex string). |
|||
See the [Method Glossary](#method-glossary) below. |
|||
|
|||
Example: `hash128("jude.id" + "8d8762c37d82360b84cf4d87f32f7754") == "d1062edb9ec9c85ad1aca6d37f2f5793"`. |
|||
|
|||
The 20 byte zone file hash is computed from zone file data by using `ripemd160(sha56(zone file data))` |
|||
|
|||
Inputs: |
|||
|
|||
- owner `scriptSig` |
|||
- payment `scriptSig`'s |
|||
|
|||
Outputs: |
|||
|
|||
- `OP_RETURN` payload |
|||
- owner's `scriptPubkey` |
|||
- payment `scriptPubkey` change |
|||
|
|||
### NAME_TRANSFER |
|||
|
|||
Op: `>` |
|||
|
|||
Description: This transaction changes the public key hash that owns the name in |
|||
BNS. |
|||
|
|||
Example: [`7a0a3bb7d39b89c3638abc369c85b5c028d0a55d7804ba1953ff19b0125f3c24`](https://www.blocktrail.com/BTC/tx/7a0a3bb7d39b89c3638abc369c85b5c028d0a55d7804ba1953ff19b0125f3c24) |
|||
|
|||
`OP_RETURN` wire format: |
|||
|
|||
``` |
|||
0 2 3 4 20 36 |
|||
|-----|--|----|-------------------|---------------| |
|||
magic op keep hash128(name.ns_id) consensus hash |
|||
data? |
|||
``` |
|||
|
|||
Inputs: |
|||
|
|||
- Owner `scriptSig` |
|||
- Payment `scriptSig`'s |
|||
|
|||
Outputs: |
|||
|
|||
- `OP_RETURN` payload |
|||
- new name owner's `scriptPubkey` |
|||
- old name owner's `scriptPubkey` |
|||
- payment `scriptPubkey` change |
|||
|
|||
Notes: |
|||
|
|||
- The `keep data?` byte controls whether or not the name's 20-byte value is preserved. This value is either `>` to preserve it, or `~` to delete it. |
|||
|
|||
### NAME_REVOKE |
|||
|
|||
Op: `~` |
|||
|
|||
Description: This transaction destroys a registered name. Its name state value |
|||
in BNS will be cleared, and no further transactions will be able to affect the |
|||
name until it expires (if its namespace allows it to expire at all). |
|||
|
|||
Example: [`eb2e84a45cf411e528185a98cd5fb45ed349843a83d39fd4dff2de47adad8c8f`](https://www.blocktrail.com/BTC/tx/eb2e84a45cf411e528185a98cd5fb45ed349843a83d39fd4dff2de47adad8c8f) |
|||
|
|||
`OP_RETURN` wire format: |
|||
|
|||
``` |
|||
0 2 3 39 |
|||
|----|--|-----------------------------| |
|||
magic op name.ns_id (37 bytes) |
|||
``` |
|||
|
|||
Inputs: |
|||
|
|||
- owner `scriptSig` |
|||
- payment `scriptSig`'s |
|||
|
|||
Outputs: |
|||
|
|||
- `OP_RETURN` payload |
|||
- owner `scriptPubkey` |
|||
- payment `scriptPubkey` change |
|||
|
|||
### ANNOUNCE |
|||
|
|||
Op: `#` |
|||
|
|||
Description: This transaction does not affect any names in BNS, but it allows a |
|||
user to send a message to other BNS nodes. In order for the message to be |
|||
received, the following must be true: |
|||
|
|||
- The sender must have a BNS name |
|||
- The BNS nodes must list the sender's BNS name as being a "trusted message |
|||
sender" |
|||
- The message must have already been propagated through the [Atlas |
|||
network](/understand-stacks/atlas-overview). This transaction references it by content hash. |
|||
|
|||
`OP_RETURN` wire format: |
|||
|
|||
``` |
|||
0 2 3 23 |
|||
|----|--|-----------------------------| |
|||
magic op ripemd160(sha256(message)) |
|||
``` |
|||
|
|||
Inputs: |
|||
|
|||
- The payer `scriptSig`'s |
|||
|
|||
Outputs: |
|||
|
|||
- `OP_RETURN` payload |
|||
- change `scriptPubKey` |
|||
|
|||
Notes: |
|||
|
|||
- The payer key should be an owner key for an existing name, since Stacks users can subscribe to announcements from specific name-owners. |
|||
|
|||
### NAMESPACE_PREORDER |
|||
|
|||
Op: `*` |
|||
|
|||
Description: This transaction announces the _hash_ of a new namespace. It is the |
|||
first of three transactions that must be sent to create a namespace. |
|||
|
|||
Example: [`5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b28`](https://www.blocktrail.com/BTC/tx/5f00b8e609821edd6f3369ee4ee86e03ea34b890e242236cdb66ef6c9c6a1b28) |
|||
|
|||
`OP_RETURN` wire format: |
|||
|
|||
``` |
|||
0 2 3 23 39 |
|||
|-----|---|-----------------------------------------|----------------| |
|||
magic op hash_name(ns_id,script_pubkey,reveal_addr) consensus hash |
|||
``` |
|||
|
|||
Inputs: |
|||
|
|||
- Namespace payer `scriptSig` |
|||
|
|||
Outputs: |
|||
|
|||
- `OP_RETURN` payload |
|||
- Namespace payer `scriptPubkey` change address |
|||
- `p2pkh` script to the burn address `1111111111111111111114oLvT2`, whose public key hash is 0x00000000000000000000000000000000 |
|||
|
|||
Notes: |
|||
|
|||
- The `reveal_addr` field is the address of the namespace revealer public key. The revealer private key will be used to generate `NAME_IMPORT` transactions. |
|||
|
|||
### NAMESPACE_REVEAL |
|||
|
|||
Op: `&` |
|||
|
|||
Description: This transaction reveals the namespace ID and namespace rules |
|||
for a previously anounced namespace hash (sent by a previous `NAMESPACE_PREORDER`). |
|||
|
|||
Example: [`ab54b1c1dd5332dc86b24ca2f88b8ca0068485edf0c322416d104c5b84133a32`](https://www.blocktrail.com/BTC/tx/ab54b1c1dd5332dc86b24ca2f88b8ca0068485edf0c322416d104c5b84133a32) |
|||
|
|||
`OP_RETURN` wire format: |
|||
|
|||
``` |
|||
0 2 3 7 8 9 10 11 12 13 14 15 16 17 18 20 39 |
|||
|-----|---|--------|-----|-----|----|----|----|----|----|-----|-----|-----|--------|----------|-------------------------| |
|||
magic op life coeff. base 1-2 3-4 5-6 7-8 9-10 11-12 13-14 15-16 nonalpha version namespace ID |
|||
bucket exponents no-vowel |
|||
discounts |
|||
``` |
|||
|
|||
Inputs: |
|||
|
|||
- Namespace payer `scriptSig`s |
|||
|
|||
Outputs: |
|||
|
|||
- `OP_RETURN` payload |
|||
- namespace revealer `scriptPubkey` |
|||
- namespace payer change `scriptPubkey` |
|||
|
|||
Notes: |
|||
|
|||
- This transaction must be sent within 1 day of the `NAMESPACE_PREORDER` |
|||
- The second output (with the namespace revealer) **must** be a `p2pkh` script |
|||
- The address of the second output **must** be the `reveal_addr` in the `NAMESPACE_PREORDER` |
|||
|
|||
Pricing: |
|||
|
|||
The rules for a namespace are as follows: |
|||
|
|||
- a name can fall into one of 16 buckets, measured by length. Bucket 16 incorporates all names at least 16 characters long. |
|||
- the pricing structure applies a multiplicative penalty for having numeric characters, or punctuation characters. |
|||
- the price of a name in a bucket is ((coeff) _ (base) ^ (bucket exponent)) / ((numeric discount multiplier) _ (punctuation discount multiplier)) |
|||
|
|||
Example: |
|||
|
|||
- base = 10 |
|||
- coeff = 2 |
|||
- nonalpha discount: 10 |
|||
- no-vowel discount: 10 |
|||
- buckets 1, 2: 9 |
|||
- buckets 3, 4, 5, 6: 8 |
|||
- buckets 7, 8, 9, 10, 11, 12, 13, 14: 7 |
|||
- buckets 15, 16+: |
|||
|
|||
With the above example configuration, the following are true: |
|||
|
|||
- The price of `john` would be 2 \* 10^8, since `john` falls into bucket 4 and has no punctuation or numerics. |
|||
- The price of `john1` would be 2 \* 10^6, since `john1` falls into bucket 5 but has a number (and thus receives a 10x discount) |
|||
- The price of `john_1` would be 2 \* 10^6, since `john_1` falls into bucket 6 but has a number and punctuation (and thus receives a 10x discount) |
|||
- The price of `j0hn_1` would be 2 \* 10^5, since `j0hn_1` falls into bucket 6 but has a number and punctuation and lacks vowels (and thus receives a 100x discount) |
|||
|
|||
### NAME_IMPORT |
|||
|
|||
Op: `;` |
|||
|
|||
Description: This transaction registers a name and some name state into a |
|||
namespace that has been revealed, but not been launched. Only the namespace |
|||
creator can import names. See the [namespace creation section](/technology/naming-system) for details. |
|||
|
|||
Example: [`c698ac4b4a61c90b2c93dababde867dea359f971e2efcf415c37c9a4d9c4f312`](https://www.blocktrail.com/BTC/tx/c698ac4b4a61c90b2c93dababde867dea359f971e2efcf415c37c9a4d9c4f312) |
|||
|
|||
`OP_RETURN` wire format: |
|||
|
|||
``` |
|||
0 2 3 39 |
|||
|----|--|-----------------------------| |
|||
magic op name.ns_id (37 bytes) |
|||
``` |
|||
|
|||
Inputs: |
|||
|
|||
- The namespace reveal `scriptSig` (with the namespace revealer's public key), or one of its first 300 extended public keys |
|||
- Any payment inputs |
|||
|
|||
Outputs: |
|||
|
|||
- `OP_RETURN` payload |
|||
- recipient `scriptPubKey` |
|||
- zone file hash (using the 20-byte hash in a standard `p2pkh` script) |
|||
- payment change `scriptPubKey` |
|||
|
|||
Notes: |
|||
|
|||
- These transactions can only be sent between the `NAMESPACE_REVEAL` and `NAMESPACE_READY`. |
|||
- The first `NAME_IMPORT` transaction **must** have a `scriptSig` input that matches the `NAMESPACE_REVEAL`'s second output (that is, the reveal output). |
|||
- Any subsequent `NAME_IMPORT` transactions **may** have a `scriptSig` input whose public key is one of the first 300 extended public keys from the `NAMESPACE_REVEAL`'s `scriptSig` public key. |
|||
|
|||
### NAMESPACE_READY |
|||
|
|||
Op: `!` |
|||
|
|||
Description: This transaction launches a namesapce. Only the namespace creator |
|||
can send this transaction. Once sent, anyone can register names in the |
|||
namespace. |
|||
|
|||
Example: [`2bf9a97e3081886f96c4def36d99a677059fafdbd6bdb6d626c0608a1e286032`](https://www.blocktrail.com/BTC/tx/2bf9a97e3081886f96c4def36d99a677059fafdbd6bdb6d626c0608a1e286032) |
|||
|
|||
`OP_RETURN` wire format: |
|||
|
|||
``` |
|||
|
|||
0 2 3 4 23 |
|||
|-----|--|--|------------| |
|||
magic op . ns_id |
|||
``` |
|||
|
|||
Inputs: |
|||
|
|||
- Namespace revealer's `scriptSig`s |
|||
|
|||
Outputs: |
|||
|
|||
- `OP_RETURN` payload |
|||
- Change output to the namespace revealer's `p2pkh` script |
|||
|
|||
Notes: |
|||
|
|||
- This transaction must be sent within 1 year of the corresponding `NAMESPACE_REVEAL` to be accepted. |
|||
|
|||
### TOKEN_TRANSFER |
|||
|
|||
Op: `$` |
|||
|
|||
Description: This transaction transfers tokens from one account to another. Only `STACKS` tokens can be transferred at this time. The transaction encodes the number of _micro-Stacks_ to send. |
|||
|
|||
Example: [`093983ca71a6a9dd041c0bdb8b3012824d726ee26fe51da8335a06e8a08c2798`](https://www.blocktrail.com/BTC/tx/093983ca71a6a9dd041c0bdb8b3012824d726ee26fe51da8335a06e8a08c2798) |
|||
|
|||
`OP_RETURN` wire format: |
|||
|
|||
``` |
|||
0 2 3 19 38 46 80 |
|||
|-----|--|--------------|----------|-----------|-------------------------| |
|||
magic op consensus_hash token_type amount (LE) scratch area |
|||
``` |
|||
|
|||
Inputs: |
|||
|
|||
- Sender's scriptSig's |
|||
|
|||
Outputs: |
|||
|
|||
- `OP_RETURN` payload |
|||
- Recipient scriptPubKey (encodes the address of the receiving account) |
|||
- Change address for the sender |
|||
|
|||
Notes: |
|||
|
|||
- The `amount` field is an 8-byte litte-endian number that encodes the number of micro-Stacks. |
|||
- The `token_type` field must be `STACKS`. All other unused bytes in this field must be `\x00`. |
|||
- The `scratch area` field is optional -- it can be up to 34 bytes, and include any data you want. |
|||
|
|||
## Method Glossary |
|||
|
|||
Some hashing primitives are used to construct the wire-format representation of each name operation. They are enumerated here: |
|||
|
|||
``` |
|||
B40_REGEX = '^[a-z0-9\-_.+]*$' |
|||
|
|||
def is_b40(s): |
|||
return isinstance(s, str) and re.match(B40_REGEX, s) is not None |
|||
|
|||
def b40_to_bin(s): |
|||
if not is_b40(s): |
|||
raise ValueError('{} must only contain characters in the b40 char set'.format(s)) |
|||
return unhexlify(charset_to_hex(s, B40_CHARS)) |
|||
|
|||
def hexpad(x): |
|||
return ('0' * (len(x) % 2)) + x |
|||
|
|||
def charset_to_hex(s, original_charset): |
|||
return hexpad(change_charset(s, original_charset, B16_CHARS)) |
|||
|
|||
def bin_hash160(s, hex_format=False): |
|||
""" s is in hex or binary format |
|||
""" |
|||
if hex_format and is_hex(s): |
|||
s = unhexlify(s) |
|||
return hashlib.new('ripemd160', bin_sha256(s)).digest() |
|||
|
|||
def hex_hash160(s, hex_format=False): |
|||
""" s is in hex or binary format |
|||
""" |
|||
if hex_format and is_hex(s): |
|||
s = unhexlify(s) |
|||
return hexlify(bin_hash160(s)) |
|||
|
|||
def hash_name(name, script_pubkey, register_addr=None): |
|||
""" |
|||
Generate the hash over a name and hex-string script pubkey. |
|||
Returns the hex-encoded string RIPEMD160(SHA256(x)), where |
|||
x is the byte string composed of the concatenation of the |
|||
binary |
|||
""" |
|||
bin_name = b40_to_bin(name) |
|||
name_and_pubkey = bin_name + unhexlify(script_pubkey) |
|||
|
|||
if register_addr is not None: |
|||
name_and_pubkey += str(register_addr) |
|||
|
|||
# make hex-encoded hash |
|||
return hex_hash160(name_and_pubkey) |
|||
|
|||
def hash128(data): |
|||
""" |
|||
Hash a string of data by taking its 256-bit sha256 and truncating it to the |
|||
first 16 bytes |
|||
""" |
|||
return hexlify(bin_sha256(data)[0:16]) |
|||
``` |
Loading…
Reference in new issue