first commit

This commit is contained in:
vesem 2021-02-13 10:19:38 -05:00
commit 8019ef9ccf
92 changed files with 18925 additions and 0 deletions

3
.dockerignore Normal file
View File

@ -0,0 +1,3 @@
.git
examples/
rsync.sh

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
config/
/rsync.sh
*.pyc
__pycache__

139
Dockerfile Normal file
View File

@ -0,0 +1,139 @@
from debian:stable-slim
LABEL maintainer="dro@arrakis.it"
SHELL ["/bin/bash", "-c"]
# Install build dependencies
RUN apt-get update -y \
&& apt-get install -y automake build-essential pkg-config libffi-dev libgmp-dev libssl-dev libtinfo-dev libsystemd-dev zlib1g-dev make g++ tmux git jq wget libncursesw5 libtool autoconf libsqlite3-dev m4 ca-certificates gcc libc6-dev \
&& apt-get clean
# Install rust
ENV RUSTUP_HOME=/usr/local/rustup \
CARGO_HOME=/usr/local/cargo \
PATH=/usr/local/cargo/bin:$PATH \
RUST_VERSION=1.47.0
RUN set -eux; \
dpkgArch="$(dpkg --print-architecture)"; \
case "${dpkgArch##*-}" in \
amd64) rustArch='x86_64-unknown-linux-gnu'; rustupSha256='49c96f3f74be82f4752b8bffcf81961dea5e6e94ce1ccba94435f12e871c3bdb' ;; \
armhf) rustArch='armv7-unknown-linux-gnueabihf'; rustupSha256='5a2be2919319e8778698fa9998002d1ec720efe7cb4f6ee4affb006b5e73f1be' ;; \
arm64) rustArch='aarch64-unknown-linux-gnu'; rustupSha256='d93ef6f91dab8299f46eef26a56c2d97c66271cea60bf004f2f088a86a697078' ;; \
i386) rustArch='i686-unknown-linux-gnu'; rustupSha256='e3d0ae3cfce5c6941f74fed61ca83e53d4cd2deb431b906cbd0687f246efede4' ;; \
*) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \
esac; \
url="https://static.rust-lang.org/rustup/archive/1.22.1/${rustArch}/rustup-init"; \
wget "$url"; \
echo "${rustupSha256} *rustup-init" | sha256sum -c -; \
chmod +x rustup-init; \
./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch}; \
rm rustup-init; \
chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \
rustup --version; \
cargo --version; \
rustc --version; \
rm -rf /var/lib/apt/lists/*;
# Install cabal
ENV PATH="/root/.cabal/bin:/root/.ghcup/bin:/root/.local/bin:$PATH"
RUN wget https://downloads.haskell.org/~cabal/cabal-install-3.2.0.0/cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz \
&& tar -xf cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz \
&& rm cabal-install-3.2.0.0-x86_64-unknown-linux.tar.xz cabal.sig \
&& mkdir -p ~/.local/bin \
&& mv cabal ~/.local/bin/ \
&& cabal update && cabal --version
# Install GHC
RUN wget https://downloads.haskell.org/ghc/8.10.2/ghc-8.10.2-x86_64-deb9-linux.tar.xz \
&& tar -xf ghc-8.10.2-x86_64-deb9-linux.tar.xz \
&& rm ghc-8.10.2-x86_64-deb9-linux.tar.xz \
&& cd ghc-8.10.2 \
&& ./configure \
&& make install \
&& cd / \
&& rm -rf /ghc-8.10.2
# Install libsodium
RUN git clone https://github.com/input-output-hk/libsodium \
&& cd libsodium \
&& git checkout 66f017f1 \
&& ./autogen.sh \
&& ./configure \
&& make \
&& make install \
&& cd .. && rm -rf libsodium
ENV LD_LIBRARY_PATH="/usr/local/lib:$LD_LIBRARY_PATH" \
PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH"
# Install cardano-node
ARG VERSION
RUN echo "Building tags/$VERSION..." \
&& echo tags/$VERSION > /CARDANO_BRANCH \
&& git clone https://github.com/input-output-hk/cardano-node.git \
&& cd cardano-node \
&& git fetch --all --recurse-submodules --tags \
&& git tag \
&& git checkout tags/$VERSION \
&& cabal configure --with-compiler=ghc-8.10.2 \
&& echo "package cardano-crypto-praos" >> cabal.project.local \
&& echo " flags: -external-libsodium-vrf" >> cabal.project.local \
&& cabal build all \
&& mkdir -p /root/.local/bin/ \
&& cp -p dist-newstyle/build/x86_64-linux/ghc-8.10.2/cardano-node-${VERSION}/x/cardano-node/build/cardano-node/cardano-node /root/.local/bin/ \
&& cp -p dist-newstyle/build/x86_64-linux/ghc-8.10.2/cardano-cli-${VERSION}/x/cardano-cli/build/cardano-cli/cardano-cli /root/.local/bin/ \
&& rm -rf /root/.cabal/packages \
&& rm -rf /usr/local/lib/ghc-8.6.5/ \
&& rm -rf /cardano-node/dist-newstyle/ \
&& rm -rf /root/.cabal/store/ghc-8.6.5
# Install cncli
#RUN git clone https://github.com/AndrewWestberg/cncli \
# && cd cncli \
# && cargo install --path . --force \
# && cncli -V \
# && cd / && rm -rf cncli
# Install tools
RUN apt-get update -y \
&& apt-get install -y vim procps dnsutils bc curl nano cron python3 python3-pip \
&& apt-get clean
RUN pip3 install pytz
# Expose ports
## cardano-node, EKG, Prometheus
EXPOSE 3000 12788 12798
# ENV variables
ENV NODE_PORT="3000" \
NODE_NAME="node1" \
NODE_TOPOLOGY="" \
NODE_RELAY="False" \
CARDANO_NETWORK="main" \
EKG_PORT="12788" \
PROMETHEUS_HOST="127.0.0.1" \
PROMETHEUS_PORT="12798" \
RESOLVE_HOSTNAMES="False" \
REPLACE_EXISTING_CONFIG="False" \
POOL_PLEDGE="100000000000" \
POOL_COST="10000000000" \
POOL_MARGIN="0.05" \
METADATA_URL="" \
PUBLIC_RELAY_IP="TOPOLOGY" \
WAIT_FOR_SYNC="True" \
AUTO_TOPOLOGY="True" \
PATH="/root/.local/bin/:/scripts/:/scripts/functions/:/cardano-node/scripts/:${PATH}" \
LD_LIBRARY_PATH="/usr/local/lib:${LD_LIBRARY_PATH}" \
CARDANO_NODE_SOCKET_PATH="DEFAULT"
# Add config
ADD cfg-templates/ /cfg-templates/
RUN mkdir -p /config/
VOLUME /config/
# Add scripts
RUN echo "source /scripts/init_node_vars" >> /root/.bashrc
ADD scripts/ /scripts/
RUN chmod -R +x /scripts/
ENTRYPOINT ["/scripts/start-cardano-node"]

300
README.md Normal file
View File

@ -0,0 +1,300 @@
# Running a Cardano Stake Pool
Visit my stake pool @ [ada.arrakis.it](https://ada.arrakis.it).
From the official [cardano-node setup](https://docs.cardano.org/projects/cardano-node/en/latest/) tutorials from IOHK.
The container downloads and builds the [cardano-node](https://github.com/input-output-hk/cardano-node.git).
It can start either a block-producing node or a relay node, or both, and connect to the cardano network. By default it will connect to the test network, you can run on other networks using the CARDANO_NETWORK environment variable, See the [Environment variables](#environment) section.
If you want to run a stake pool, the block-producing container can take all the required steps to set up and register the stake pool.
## Steps in Running a Stake Pool
### Reasonably secure
This is an example on how to run your staking pool in a reasonably securely way, by keeping your `cold-keys` and `wallets` away from the online block-producing node. It is always a trade-off between security and convenience, but I find this method to be reasonably secure, if you can some precautions, as described in the below setup.
For this setup you will need 3 hosts.
`host1` for running the relay node.
`host2` host for running the block-producing node.
`host3` host for generating and registering all the keys, addresses and certificates and storing the cold-keys for refreshing the KES keys and certificates. This can be a host you are running locally, for example a secure linux live boot, with all incoming traffic completely shut off. **Warning:** If you run on a Linux live boot, with no persistant storage, it is EXTREMELY important that you backup your staking directory containing all the private keys, before you shut it off, otherwise your wallets will be lost.
1. Upload your stake-pool metadata json file ([See example](#metadata-example)) to a host so it is accessible to the public. For example as a [github gist](https://gist.github.com/).
2. Start a relay node on `host1` and make it connect to the block-producing node on `host2`. See the [relay node example](#relay-example2).
3. Start a registration node on `host3`, with the `--staking` and`--create` arguments, and make it connect to the relay node on `host1`. See the [registration node example](#registration-example2).
4. Fund your payment address generated and displayed in Step 3 to finalize the registration.
5. Wait for the registration node on `host3` to setup and register your pool.
6. Create Firewall rules for your block-producing node on `host2` to only accept incoming traffic from your relay node on `host1`.
7. Copy the `config/staking/pool-keys` directory from the registration node on `host3` to the `config/staking/pool-keys` directory on `host2`.
8. Start a block-producing node on `host2`, with the `--start` and `--staking` arguments, and make it connect to the relay node on `host1`. See the [block-producing node example](#producing-example2).
#### Renewing KES keys and certificates
To renew your KES keys and certificates you have to run the `generate_operational_certificate` command in the registration container on `host3`
The status window in the block-producing container will tell you when you have to generate new keys.
1. Start the command-line interface in the registration container, containing the `cold-keys` directory, on `host3`. Using `docker exec -it main-registration bash`.
2. Run the `generate_operational_certificate` command and wait for it to complete.
3. Copy the `config/staking/pool-keys/` directory on `host3` to the `config/staking/pool-keys/` directory on `host2`
4. Restart the block-producing container on `host2`.
#### relay node on mainnet <a id="relay-example2"></a>
Step 1. Run on `host1`. See `examples/main-relay1.sh`.
```
docker network create -d bridge cardano
docker run -it \
--restart=unless-stopped \
--network=cardano \
--name main-relay1 \
-e HOST_ADDR="0.0.0.0" \
-p 3000:3000 \
-p 12798:12798 \
-e NODE_PORT="3000" \
-e NODE_NAME="relay1" \
-e NODE_TOPOLOGY="<IP-address of block-producing node>:3000/1" \
-e NODE_RELAY="True" \
-e CARDANO_NETWORK="main" \
-e PROMETHEUS_PORT="12798" \
-v $PWD/config/:/config/ \
arradev/cardano-node:latest --start
```
#### registration node on mainnet <a id="registration-example2"></a>
Step 2. Run on `host3`. See `examples/main-registration.sh`.
```
docker network create -d bridge cardano
docker run -it --rm \
--name main-registration \
--network=cardano \
-e NODE_PORT="3000" \
-e NODE_NAME="registration" \
-e NODE_TOPOLOGY="<IP-address of relay1 node>:3000/1" \
-e CARDANO_NETWORK="main" \
-e CREATE_STAKEPOOL="True" \
-e POOL_PLEDGE="100000000000" \
-e POOL_COST="340000000" \
-e POOL_MARGIN="0.05" \
-e METADATA_URL="<URL of metadata.json>" \
-v $PWD/config/:/config/ \
arradev/cardano-node:latest --start --staking
```
#### block-producing node on mainnet <a id="producing-example2"></a>
Step 5. Run on `host2`. See `examples/main-producing.sh`.
```
docker network create -d bridge cardano
docker run -it --rm \
--network=cardano \
--name main-producing \
-p 3000:3000 \
-p 12798:12798 \
-e HOST_ADDR="0.0.0.0" \
-e NODE_PORT="3000" \
-e NODE_NAME="block-producing" \
-e NODE_TOPOLOGY="<IP-address of relay1 node>:3000/1" \
-e CARDANO_NETWORK="main" \
-e PROMETHEUS_PORT="12798" \
-v $PWD/config/:/config/ \
arradev/cardano-node:latest --start --staking
```
### Best practice
<details>
<summary>Click to expand</summary>
This is an example on how to run your staking pool in a completely secure way, by only keeping your `cold-keys` and `wallets` on a completely offline node, and then transfer all relevant registration transactions and `pool-keys` to the online block-producing node. This requires a bit more steps than the reasonably secure method.
For this setup you will need 3 hosts.
`host1` for running the relay node.
`host2` host for running the block-producing node and submitting the registration transactions.
`host3` host for generating all the keys, addresses, certificates and transactions, and storing the cold-keys for refreshing the KES keys and certificates. This must be an completely offline host running locally.
1. Upload your stake-pool metadata json file ([See example](#metadata-example)) to a host so it is accessible to the public. For example as a [github gist](https://gist.github.com/).
2. Start a relay node on `host1` and make it connect to the block-producing node on `host2`.
3. Generate `protocol.json` on `host1` by running `get_protocol`.
4. Transfer the `protocol.json` from `host1` to the staking directory of `host3`.
5. Add the `metadata.json` file to `config/staking` directory the on `host3`
6. Start a cold-creation node `host3` using the `--create-cold` argument, and follow steps.
7. Fund your owners payment address(es) created on `host3`, make sure you send to the correct addresses.
8. Get UTXO and TXIX for funded owners payment address(es) by quering the address(es) on `host1` or `host2`.
9. Input the relevant UTXO and TXIX values when promted on `host3`.
10. Find the slot tip of the blockchain by running `get_slot` on `host1` or `host2`.
11. Input the slot tip on `host3` when prompted.
12. Create Firewall rules for your block-producing node on `host2` to only accept incoming traffic from your relay node on `host1`.
13. Upload staking-hot.tar.gz on `host2`
14. Start a block-producing node on `host2`, with the `--start`, `--staking` and `--register-cold` arguments, and make it connect to the relay node on `host1`.
15. Wait for the block-producing node on `host2` to register your pool and start staking.
See examples of the containers in `examples/best-practice/`.
</details>
### Test setup
<details>
<summary>Click to expand</summary>
**Warning:** These examples are ONLY for demonstration. The examples will run the nodes on the same server, using the `host` network, and connects to eachother using the localhost IP-address. This is not recommended. It is recommended to run the nodes on seperate servers and connect them using their public or local network IP-addresses, if they run within the same network. The idea is to keep the block-producing node completely locked off from anything other than the relay node. The block-producing node will also initialize and register the stake pool automatically, which is better to do on a seperate node, to keep the `cold-keys` directory and `wallets` secret key files (`wallets/*/*.skey`) completely away from the online nodes.
1. Upload your stake-pool metadata json file ([See example](#metadata-example)) to a host so it is accessible to the public. For example as a [github gist](https://gist.github.com/).
2. Start a relay node and make it connect to the block-producing node. See the `examples/mc4-relay1.sh` example file.
3. Start a block-producing node with the `--start`, `--staking` and `--create` arguments, and make it connect to the relay node. See the `examples/mc4-producing.sh` example file.
4. Wait for the block-producing node to setup and register your pool.
5. Fund your payment address generated and displayed in Step 4 to finalize the registration.
The docker-compose file `examples/test/mc4-docker-compose.yaml` will run these 2 containers automatically. Use the command `docker-compose -f mc4-docker-compose.yaml up` to start them.
</details>
## Monitoring
If you want to monitor your nodes using prometheus across different hosts, you can set the environment variable `PROMETHEUS_HOST=0.0.0.0`. This makes the Prometheus service accessible to other hosts. So you can for example run a Prometheus+Grafana service on your relay node, scraping data from the block-producing and relay nodes.
If you do this, it is EXTREMELY important that you set up a Firewall rule ONLY allowing traffic from your relay nodes host on the Prometheus port, otherwise everyone will be able to monitor your node.
## Metadata example <a id="metadata-example"></a>
The `examples/metadata.json` file is the file that holds metadata about your pool.
It looks like the following, and has to be upload to a host so it is accessible to the public via. an URL.
You can for example upload it as a [github gist](https://gist.github.com).
```
{
"name": "Example Pool",
"description": "Cardano stakepool example",
"ticker": "TEST",
"homepage": "https://github.com/abracadaniel/cardano-node-docker"
}
```
## Arguments
You can pass the following arguments to the start up script.
| Argument | Function |
| :-- | -- |
| --start | Start node. |
| --create | Start Stakepool creation. Initializes Stake Pool keys, addresses and certificates, and sends them to the blockchain, when starting as a stakepool, if it is not already initialized. |
| --cold-create | Initializes Stake Pool keys, addresses and certificates, and sign registration transactions. Registation transactions has to be sent using the `--cold-register` argument. |
| --cold-register | Submits the address and pool registration transactions to the blockchain created using the `--cold-create` argument. |
| --staking | Start as a staking node (Requires the `--start` argument) |
| --cli | Start command-line interface. |
| --update | Update the node software. |
| --init_config | Initialize config. |
| --help | see this message. |
## Environment variables <a id="environment"></a>
You can pass the following environment variables to the container.
| Variable | Function |
| :-- | -- |
| NODE_PORT | Port of node. Default: 3000. |
| NODE_NAME | Name of node. Default: node1. |
| NODE_TOPOLOGY | Topology of the node. Should be comma separated for each individual node to add, on the form: \<ip\>:\<port\>/\<valency\>. So for example: 127.0.0.1:3001/1,127.0.0.1:3002/1. |
| NODE_RELAY | Set to True if default IOHK relay should be added to the network topology. Default: False. |
| HOST_ADDR | Set cardano-node host address. Defaults to public IP address. |
| CARDANO_NETWORK | Carano network to use (main, test, pioneer). Default: main. |
| EKG_PORT | Port of EKG monitoring. Default: 12788. |
| PROMETHEUS_HOST | Host of Prometheus monitoring. Default: 127.0.0.1. |
| PROMETHEUS_PORT | Port of Prometheus monitoring. Default: 12798. |
| RESOLVE_HOSTNAMES | Resolve topology hostnames to IP-addresses. Default: False. |
| REPLACE_EXISTING_CONFIG | Reset and replace existing configs. Default: False. |
| POOL_PLEDGE | Pledge (lovelace). Default: 100000000000 |
| POOL_COST | Operational costs per epoch (lovelace). Default: 10000000000 |
| POOL_MARGIN | Operator margin. Default: 0.05 |
| METADATA_URL | URL for file containing stake pool metadata information. See \`examples/metadata.json\` for examle. The file be uploaded to an URL accessible to public. |
| MULTI_OWNERS | Define multiple stakepool owner wallets which participates in the stakepool pledge. Comma separated values. Example: owner2,owner3. If the wallets do not exist they will automatically be created. Default: None. |
| PUBLIC_RELAY_IP | Public IP address of Relay node. <br/><br/>Values:<br/>\<Any IP address\><br/>TOPOLOGY: Use first entry of the topology.<br/>PUBLIC: Use public IP of node.<br/>Default: TOPOLOGY. |
| PUBLIC_RELAY_PORT | Public port of Relay node. <br/><br/>Values:<br/>\<Any Port\><br/>If PUBLIC_RELAY_IP=TOPOLOGY the PUBLIC_RELAY_PORT will also be updated accordingly.<br/>Default: First entry of the topology. |
| AUTO_TOPOLOGY | Automatically update topology.json. Default: True |
## Commands
These commands can be run from the command-line interface of the container.
| Command | Description |
| :-- | -- |
| create_stakepool | Take all the steps to initialize and register the stakepool from scratch. |
| generate_stake_address | Generate payment and stake keys and addresses. |
| generate_registration_certificates | Generates stakepool registration certificates. |
| generate_operational_certificates | Generates stakepool cold-keys, and VRF and KES keys, and the node certificates. |
| register_stake_address | Registers your stake address in the blockchain. |
| register_stake_pool | Registers your stake pool in the blockchain. |
| sync_status | Display node synchronization status. |
## Supported Networks
Use the CARDANO_NETWORK environment variable to change this.
The latest supported networks can be found at [https://hydra.iohk.io/job/Cardano/cardano-node/cardano-deployment/latest-finished/download/1/index.html](https://hydra.iohk.io/job/Cardano/cardano-node/cardano-deployment/latest-finished/download/1/index.html)
| Network | CARDANO_NETWORK value |
| :-- | -- |
| mainnet | main |
| mainnet-candidate4 | mc4 |
## Ports
| Port | Function |
| :-- | -- |
| 3000 | Default port cardano-node. |
| 12798 | Default port for Prometheus monitoring. |
## Volumes
| Volume | Function |
| :-- | -- |
| /config | Specify a folder to store the configuration and database of the nodes, for persistent data. |
## Example scripts
Use these example scripts to see how the nodes can be started.
| Script | Description |
| :-- | -- |
| test/mc4-docker-compose.yaml | docker compose file for running relay node and block-producing node locally on mainnet-candidate4, and initialize and register the stakepool |
| best-practice/mc4-relay1.sh | Run relay node locally on mainnet-candidate4. |
| best-practice/mc4-producing.sh | Run block-producing node locally on mainnet-candidate4 and initialize and register the it as a stakepool. |
| best-practice/mc4-cold-create.sh | Local cold creation on mainnet-candidate4. |
| main-relay1.sh | Run relay node locally on mainnet. |
| main-producing.sh | Run block-producing node on mainnet. |
| main-registration.sh | Run block-producing node on mainnet and initialize and register the it as a stakepool. |
## Docker hub
Image can be found [here](https://hub.docker.com/repository/docker/arradev/cardano-node).
## Building locally
If you want to make local modifications to these images for development purposes or just to customize the logic.
```
git clone https://github.com/abracadaniel/cardano-node-docker.git
cd cardano-node-docker
./build.sh
```
## Thank you
I hope you will find this useful. If you like the work please consider delegating to my pool:
`[ARRA1] Arrakis (c65ca06828caa8fc9b0bb015af93ef71685544c6ed2abbb7c59b0e62)`
or donating a few ADA to:
`addr1qyfdc9rkw2njpevpene998w93uyghftspnv6muxkwt82tyyjn4up3dddmmul3a5p98996dyd5nhn2mwthwce6rjrp0espmglvg`

7
build.sh Normal file
View File

@ -0,0 +1,7 @@
#!/bin/bash
VERSION="1.25.1"
docker build \
--build-arg VERSION=${VERSION} \
--tag arradev/cardano-node:${VERSION} \
--tag arradev/cardano-node:latest .

1
cfg-templates/crontab Normal file
View File

@ -0,0 +1 @@
30 * * * * /scripts/topology_submit

2
cfg-templates/main/VARS Normal file
View File

@ -0,0 +1,2 @@
export NETWORK_ARGUMENT="--mainnet"
export HARDFORK_EPOCH=208

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,155 @@
{
"ApplicationName": "cardano-sl",
"ApplicationVersion": 1,
"ByronGenesisFile": "mainnet-byron-genesis.json",
"ByronGenesisHash": "5f20df933584822601f9e3f8c024eb5eb252fe8cefb24d1317dc3d432e940ebb",
"LastKnownBlockVersion-Alt": 0,
"LastKnownBlockVersion-Major": 3,
"LastKnownBlockVersion-Minor": 0,
"MaxKnownMajorProtocolVersion": 2,
"Protocol": "Cardano",
"RequiresNetworkMagic": "RequiresNoMagic",
"ShelleyGenesisFile": "mainnet-shelley-genesis.json",
"ShelleyGenesisHash": "1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81",
"TraceBlockFetchClient": false,
"TraceBlockFetchDecisions": false,
"TraceBlockFetchProtocol": false,
"TraceBlockFetchProtocolSerialised": false,
"TraceBlockFetchServer": false,
"TraceChainDb": true,
"TraceChainSyncBlockServer": false,
"TraceChainSyncClient": false,
"TraceChainSyncHeaderServer": false,
"TraceChainSyncProtocol": false,
"TraceDNSResolver": true,
"TraceDNSSubscription": true,
"TraceErrorPolicy": true,
"TraceForge": true,
"TraceHandshake": false,
"TraceIpSubscription": true,
"TraceLocalChainSyncProtocol": false,
"TraceLocalErrorPolicy": true,
"TraceLocalHandshake": false,
"TraceLocalTxSubmissionProtocol": false,
"TraceLocalTxSubmissionServer": false,
"TraceMempool": true,
"TraceMux": false,
"TraceTxInbound": false,
"TraceTxOutbound": false,
"TraceTxSubmissionProtocol": false,
"TracingVerbosity": "NormalVerbosity",
"TurnOnLogMetrics": true,
"TurnOnLogging": true,
"defaultBackends": [
"KatipBK"
],
"defaultScribes": [
[
"StdoutSK",
"stdout"
]
],
"hasEKG": 12788,
"hasPrometheus": [
"127.0.0.1",
12798
],
"minSeverity": "Info",
"options": {
"mapBackends": {
"cardano.node-metrics": [
"EKGViewBK"
],
"cardano.node.BlockFetchDecision.peers": [
"EKGViewBK"
],
"cardano.node.ChainDB.metrics": [
"EKGViewBK"
],
"cardano.node.Forge.metrics": [
"EKGViewBK"
],
"cardano.node.metrics": [
"EKGViewBK"
],
"cardano.node.resources": [
"EKGViewBK"
]
},
"mapSubtrace": {
"#ekgview": {
"contents": [
[
{
"contents": "cardano.epoch-validation.benchmark",
"tag": "Contains"
},
[
{
"contents": ".monoclock.basic.",
"tag": "Contains"
}
]
],
[
{
"contents": "cardano.epoch-validation.benchmark",
"tag": "Contains"
},
[
{
"contents": "diff.RTS.cpuNs.timed.",
"tag": "Contains"
}
]
],
[
{
"contents": "#ekgview.#aggregation.cardano.epoch-validation.benchmark",
"tag": "StartsWith"
},
[
{
"contents": "diff.RTS.gcNum.timed.",
"tag": "Contains"
}
]
]
],
"subtrace": "FilterTrace"
},
"benchmark": {
"contents": [
"GhcRtsStats",
"MonotonicClock"
],
"subtrace": "ObservableTrace"
},
"cardano.epoch-validation.utxo-stats": {
"subtrace": "NoTrace"
},
"cardano.node-metrics": {
"subtrace": "Neutral"
},
"cardano.node.metrics": {
"subtrace": "Neutral"
}
}
},
"rotation": {
"rpKeepFilesNum": 10,
"rpLogLimitBytes": 5000000,
"rpMaxAgeHours": 24
},
"setupBackends": [
"KatipBK"
],
"setupScribes": [
{
"scFormat": "ScText",
"scKind": "StdoutSK",
"scName": "stdout",
"scRotation": null
}
]
}

View File

@ -0,0 +1,121 @@
{
"ByronGenesisFile": "/nix/store/3678ccikas3q16jcqcghwviqsd5k9wjx-mainnet-byron-genesis.json",
"ByronGenesisHash": "5f20df933584822601f9e3f8c024eb5eb252fe8cefb24d1317dc3d432e940ebb",
"EnableLogMetrics": false,
"EnableLogging": true,
"NetworkName": "mainnet",
"Protocol": "Cardano",
"RequiresNetworkMagic": "RequiresNoMagic",
"ShelleyGenesisFile": "/nix/store/hxgam7f415s8b0j6c3qwakgkzd0pr5h4-mainnet-shelley-genesis.json",
"ShelleyGenesisHash": "1a3be38bcbb7911969283716ad7aa550250226b76a61fc51cc9a9a35d9276d81",
"defaultBackends": [
"KatipBK"
],
"defaultScribes": [
[
"StdoutSK",
"stdout"
]
],
"hasPrometheus": [
"127.0.0.1",
12698
],
"minSeverity": "Info",
"options": {
"cfokey": {
"value": "Release-1.0.0"
},
"mapBackends": {},
"mapSeverity": {
"db-sync-node": "Info",
"db-sync-node.Mux": "Error",
"db-sync-node.Subscription": "Error"
},
"mapSubtrace": {
"#ekgview": {
"contents": [
[
{
"contents": "cardano.epoch-validation.benchmark",
"tag": "Contains"
},
[
{
"contents": ".monoclock.basic.",
"tag": "Contains"
}
]
],
[
{
"contents": "cardano.epoch-validation.benchmark",
"tag": "Contains"
},
[
{
"contents": "diff.RTS.cpuNs.timed.",
"tag": "Contains"
}
]
],
[
{
"contents": "#ekgview.#aggregation.cardano.epoch-validation.benchmark",
"tag": "StartsWith"
},
[
{
"contents": "diff.RTS.gcNum.timed.",
"tag": "Contains"
}
]
]
],
"subtrace": "FilterTrace"
},
"#messagecounters.aggregation": {
"subtrace": "NoTrace"
},
"#messagecounters.ekgview": {
"subtrace": "NoTrace"
},
"#messagecounters.katip": {
"subtrace": "NoTrace"
},
"#messagecounters.monitoring": {
"subtrace": "NoTrace"
},
"#messagecounters.switchboard": {
"subtrace": "NoTrace"
},
"benchmark": {
"contents": [
"GhcRtsStats",
"MonotonicClock"
],
"subtrace": "ObservableTrace"
},
"cardano.epoch-validation.utxo-stats": {
"subtrace": "NoTrace"
}
}
},
"rotation": {
"rpKeepFilesNum": 10,
"rpLogLimitBytes": 5000000,
"rpMaxAgeHours": 24
},
"setupBackends": [
"AggregationBK",
"KatipBK"
],
"setupScribes": [
{
"scFormat": "ScText",
"scKind": "StdoutSK",
"scName": "stdout",
"scRotation": null
}
]
}

View File

@ -0,0 +1,114 @@
{
"EnableLogMetrics": false,
"EnableLogging": true,
"defaultBackends": [
"KatipBK"
],
"defaultScribes": [
[
"StdoutSK",
"stdout"
]
],
"hasPrometheus": [
"127.0.0.1",
12698
],
"minSeverity": "Info",
"options": {
"cfokey": {
"value": "Release-1.0.0"
},
"mapBackends": {},
"mapSeverity": {
"db-sync-node": "Info",
"db-sync-node.Mux": "Error",
"db-sync-node.Subscription": "Error"
},
"mapSubtrace": {
"#ekgview": {
"contents": [
[
{
"contents": "cardano.epoch-validation.benchmark",
"tag": "Contains"
},
[
{
"contents": ".monoclock.basic.",
"tag": "Contains"
}
]
],
[
{
"contents": "cardano.epoch-validation.benchmark",
"tag": "Contains"
},
[
{
"contents": "diff.RTS.cpuNs.timed.",
"tag": "Contains"
}
]
],
[
{
"contents": "#ekgview.#aggregation.cardano.epoch-validation.benchmark",
"tag": "StartsWith"
},
[
{
"contents": "diff.RTS.gcNum.timed.",
"tag": "Contains"
}
]
]
],
"subtrace": "FilterTrace"
},
"#messagecounters.aggregation": {
"subtrace": "NoTrace"
},
"#messagecounters.ekgview": {
"subtrace": "NoTrace"
},
"#messagecounters.katip": {
"subtrace": "NoTrace"
},
"#messagecounters.monitoring": {
"subtrace": "NoTrace"
},
"#messagecounters.switchboard": {
"subtrace": "NoTrace"
},
"benchmark": {
"contents": [
"GhcRtsStats",
"MonotonicClock"
],
"subtrace": "ObservableTrace"
},
"cardano.epoch-validation.utxo-stats": {
"subtrace": "NoTrace"
}
}
},
"rotation": {
"rpKeepFilesNum": 10,
"rpLogLimitBytes": 5000000,
"rpMaxAgeHours": 24
},
"setupBackends": [
"AggregationBK",
"KatipBK"
],
"setupScribes": [
{
"scFormat": "ScText",
"scKind": "StdoutSK",
"scName": "stdout",
"scRotation": null
}
]
}

View File

@ -0,0 +1,68 @@
{
"activeSlotsCoeff": 0.05,
"protocolParams": {
"protocolVersion": {
"minor": 0,
"major": 2
},
"decentralisationParam": 1,
"eMax": 18,
"extraEntropy": {
"tag": "NeutralNonce"
},
"maxTxSize": 16384,
"maxBlockBodySize": 65536,
"maxBlockHeaderSize": 1100,
"minFeeA": 44,
"minFeeB": 155381,
"minUTxOValue": 1000000,
"poolDeposit": 500000000,
"minPoolCost": 340000000,
"keyDeposit": 2000000,
"nOpt": 150,
"rho": 0.003,
"tau": 0.20,
"a0": 0.3
},
"genDelegs": {
"ad5463153dc3d24b9ff133e46136028bdc1edbb897f5a7cf1b37950c": {
"delegate": "d9e5c76ad5ee778960804094a389f0b546b5c2b140a62f8ec43ea54d",
"vrf": "64fa87e8b29a5b7bfbd6795677e3e878c505bc4a3649485d366b50abadec92d7"
},
"b9547b8a57656539a8d9bc42c008e38d9c8bd9c8adbb1e73ad529497": {
"delegate": "855d6fc1e54274e331e34478eeac8d060b0b90c1f9e8a2b01167c048",
"vrf": "66d5167a1f426bd1adcc8bbf4b88c280d38c148d135cb41e3f5a39f948ad7fcc"
},
"60baee25cbc90047e83fd01e1e57dc0b06d3d0cb150d0ab40bbfead1": {
"delegate": "7f72a1826ae3b279782ab2bc582d0d2958de65bd86b2c4f82d8ba956",
"vrf": "c0546d9aa5740afd569d3c2d9c412595cd60822bb6d9a4e8ce6c43d12bd0f674"
},
"f7b341c14cd58fca4195a9b278cce1ef402dc0e06deb77e543cd1757": {
"delegate": "69ae12f9e45c0c9122356c8e624b1fbbed6c22a2e3b4358cf0cb5011",
"vrf": "6394a632af51a32768a6f12dac3485d9c0712d0b54e3f389f355385762a478f2"
},
"162f94554ac8c225383a2248c245659eda870eaa82d0ef25fc7dcd82": {
"delegate": "4485708022839a7b9b8b639a939c85ec0ed6999b5b6dc651b03c43f6",
"vrf": "aba81e764b71006c515986bf7b37a72fbb5554f78e6775f08e384dbd572a4b32"
},
"2075a095b3c844a29c24317a94a643ab8e22d54a3a3a72a420260af6": {
"delegate": "6535db26347283990a252313a7903a45e3526ec25ddba381c071b25b",
"vrf": "fcaca997b8105bd860876348fc2c6e68b13607f9bbd23515cd2193b555d267af"
},
"268cfc0b89e910ead22e0ade91493d8212f53f3e2164b2e4bef0819b": {
"delegate": "1d4f2e1fda43070d71bb22a5522f86943c7c18aeb4fa47a362c27e23",
"vrf": "63ef48bc5355f3e7973100c371d6a095251c80ceb40559f4750aa7014a6fb6db"
}
},
"updateQuorum": 5,
"networkId": "Mainnet",
"initialFunds": {},
"maxLovelaceSupply": 45000000000000000,
"networkMagic": 764824073,
"epochLength": 432000,
"systemStart": "2017-09-23T21:44:51Z",
"slotsPerKESPeriod": 129600,
"slotLength": 1,
"maxKESEvolutions": 62,
"securityParam": 2160
}

View File

@ -0,0 +1,9 @@
{
"Producers": [
{
"addr": "relays-new.cardano-mainnet.iohk.io",
"port": 3001,
"valency": 2
}
]
}

View File

@ -0,0 +1,3 @@
{
"Producers": []
}

2
cfg-templates/mc4/VARS Normal file
View File

@ -0,0 +1,2 @@
export NETWORK_ARGUMENT="--testnet-magic 42"
export HARDFORK_EPOCH=1

View File

@ -0,0 +1,63 @@
{ "bootStakeholders":
{ "473cfa74426964f50d93973de6b0f2e40f3320fe9e670ed1e891de10": 1
, "c1b2ae2a90a808788615fa96a01ced3a6e67e669348efded4eaed473": 1
, "da379ef48add30b195d9b8bdafc2fdf5998753a7959ad26320bf2ebe": 1
}
, "heavyDelegation":
{ "473cfa74426964f50d93973de6b0f2e40f3320fe9e670ed1e891de10":
{ "omega": 0
, "issuerPk":
"5jlrrnjBpWzFOE84xc6uh8Ke1Be/NEcIYW3f0n1C8zGDSCZwNd1xm40Zu7Ri+6hcCScaa93KA39gNFn0mtZOSw=="
, "delegatePk":
"gPSUJ9TxeDi3mn8pWrztZvChWsDIqkuuwVxfU6cm2CwP8vFNgfBo7mMFJwxdsG08xraJ4qXbIWynAmTfeHL0Tg=="
, "cert":
"5544f210551803bfbcffbeeb807503d2cfa3909131248c12594a0feaf13b939d2e9eb81d8e8e667a688659d7714cbf3b16841b264b393de32b6f3d0f2a041307"
}
, "c1b2ae2a90a808788615fa96a01ced3a6e67e669348efded4eaed473":
{ "omega": 0
, "issuerPk":
"RYaRZCsjTNYMojPGW1hAGZcYaWY84stEXQd95FqVyLxU0iDoEHP1Oh9+5xxyPEGZ9z5jxCva0WpE+4AVtyQy4Q=="
, "delegatePk":
"CswJCLqUCrDQa5pb4NX8uQlv8uy7ZxbjnD5cSAIvgf4G9Ql0ZaA7wnS4yjJysi5uZyV2qnwwt3koP6djhvwuJQ=="
, "cert":
"25cade766847eabc070cf8dee62bfbf315676a7805fb2d5058c981edab1150f2e24ad9f8a64a1f178076955506e1920d10564637852561ba821c231aa0478d03"
}
, "da379ef48add30b195d9b8bdafc2fdf5998753a7959ad26320bf2ebe":
{ "omega": 0
, "issuerPk":
"g4lK99OuTyyRDTCK4772Z56CM+KsLX5PIDkd5wBRhEHvbFBiPVno3o+5HZ07wZrKRDCdYH4NINuJ8WR7oSRsIQ=="
, "delegatePk":
"+lqfLp1qM/vGMJvmeRgpl82ECWFzvKR5JulHnjrkfhg0Cn2LK/4c+IQrtp/zu4dzHOaCHj+zqmunrdomMlgNug=="
, "cert":
"cc6d1fd828841c47adbb9968f7cfd86770380001762b354a09fc84a6d17d05c116e8723f90b70469a5231a7f35851b79b2ed9f1526ade3f1f5c65ae9def56a09"
}
}
, "startTime": 1595682000
, "nonAvvmBalances":
{ "Ae2tdPwUPEYyv5UFN9PSgqfquhfkpxsv6M8h7K223pSL4JAnxGCGSGJq6wU":
"33000000000000000"
}
, "blockVersionData":
{ "scriptVersion": 0
, "slotDuration": "20000"
, "maxBlockSize": "2000000"
, "maxHeaderSize": "2000000"
, "maxTxSize": "4096"
, "maxProposalSize": "700"
, "mpcThd": "20000000000000"
, "heavyDelThd": "300000000000"
, "updateVoteThd": "1000000000000"
, "updateProposalThd": "100000000000000"
, "updateImplicit": "10000"
, "softforkRule":
{ "initThd": "900000000000000"
, "minThd": "600000000000000"
, "thdDecrement": "50000000000000"
}
, "txFeePolicy":
{ "summand": "155381000000000" , "multiplier": "43946000000" }
, "unlockStakeEpoch": "18446744073709551615"
}
, "protocolConsts": { "k": 108 , "protocolMagic": 42 }
, "avvmDistr": {}
}

View File

@ -0,0 +1,171 @@
{
"ApplicationName": "cardano-sl",
"ApplicationVersion": 0,
"ByronGenesisFile": "mainnet_candidate_4-byron-genesis.json",
"ByronGenesisHash": "406bd7edfa14db46edb367d18f5b3dba8d0c626b7c1c19f283867a70d05945c9",
"LastKnownBlockVersion-Alt": 0,
"LastKnownBlockVersion-Major": 2,
"LastKnownBlockVersion-Minor": 0,
"MaxKnownMajorProtocolVersion": 2,
"PBftSignatureThreshold": 0.9,
"Protocol": "Cardano",
"RequiresNetworkMagic": "RequiresNoMagic",
"ShelleyGenesisFile": "mainnet_candidate_4-shelley-genesis.json",
"ShelleyGenesisHash": "ef8a74ab8587db4c95a7b98cd15406faf7044d9ff47b977f54053f7ad4fd9e59",
"TestShelleyHardForkAtEpoch": 1,
"TraceBlockFetchClient": false,
"TraceBlockFetchDecisions": false,
"TraceBlockFetchProtocol": false,
"TraceBlockFetchProtocolSerialised": false,
"TraceBlockFetchServer": false,
"TraceChainDb": true,
"TraceChainSyncBlockServer": false,
"TraceChainSyncClient": false,
"TraceChainSyncHeaderServer": false,
"TraceChainSyncProtocol": false,
"TraceDNSResolver": true,
"TraceDNSSubscription": true,
"TraceErrorPolicy": true,
"TraceForge": true,
"TraceHandshake": false,
"TraceIpSubscription": true,
"TraceLocalChainSyncProtocol": false,
"TraceLocalErrorPolicy": true,
"TraceLocalHandshake": false,
"TraceLocalTxSubmissionProtocol": false,
"TraceLocalTxSubmissionServer": false,
"TraceMempool": true,
"TraceMux": false,
"TraceTxInbound": false,
"TraceTxOutbound": false,
"TraceTxSubmissionProtocol": false,
"TracingVerbosity": "NormalVerbosity",
"TurnOnLogMetrics": true,
"TurnOnLogging": true,
"ViewMode": "SimpleView",
"defaultBackends": [
"KatipBK"
],
"defaultScribes": [
[
"StdoutSK",
"stdout"
]
],
"hasEKG": 12788,
"hasPrometheus": [
"127.0.0.1",
12798
],
"minSeverity": "Info",
"options": {
"mapBackends": {
"cardano.node-metrics": [
"EKGViewBK",
{
"kind": "UserDefinedBK",
"name": "LiveViewBackend"
}
],
"cardano.node.BlockFetchDecision.peers": [
"EKGViewBK",
{
"kind": "UserDefinedBK",
"name": "LiveViewBackend"
}
],
"cardano.node.ChainDB.metrics": [
"EKGViewBK",
{
"kind": "UserDefinedBK",
"name": "LiveViewBackend"
}
],
"cardano.node.Forge.metrics": [
"EKGViewBK"
],
"cardano.node.metrics": [
"EKGViewBK",
{
"kind": "UserDefinedBK",
"name": "LiveViewBackend"
}
]
},
"mapSubtrace": {
"#ekgview": {
"contents": [
[
{
"contents": "cardano.epoch-validation.benchmark",
"tag": "Contains"
},
[
{
"contents": ".monoclock.basic.",
"tag": "Contains"
}
]
],
[
{
"contents": "cardano.epoch-validation.benchmark",
"tag": "Contains"
},
[
{
"contents": "diff.RTS.cpuNs.timed.",
"tag": "Contains"
}
]
],
[
{
"contents": "#ekgview.#aggregation.cardano.epoch-validation.benchmark",
"tag": "StartsWith"
},
[
{
"contents": "diff.RTS.gcNum.timed.",
"tag": "Contains"
}
]
]
],
"subtrace": "FilterTrace"
},
"benchmark": {
"contents": [
"GhcRtsStats",
"MonotonicClock"
],
"subtrace": "ObservableTrace"
},
"cardano.epoch-validation.utxo-stats": {
"subtrace": "NoTrace"
},
"cardano.node-metrics": {
"subtrace": "Neutral"
},
"cardano.node.metrics": {
"subtrace": "Neutral"
}
}
},
"rotation": {
"rpKeepFilesNum": 10,
"rpLogLimitBytes": 5000000,
"rpMaxAgeHours": 24
},
"setupBackends": [
"KatipBK"
],
"setupScribes": [
{
"scFormat": "ScText",
"scKind": "StdoutSK",
"scName": "stdout",
"scRotation": null
}
]
}

View File

@ -0,0 +1,52 @@
{
"activeSlotsCoeff": 0.05,
"protocolParams": {
"protocolVersion": {
"minor": 0,
"major": 2
},
"decentralisationParam": 1,
"eMax": 18,
"extraEntropy": {
"tag": "NeutralNonce"
},
"maxTxSize": 16384,
"maxBlockBodySize": 65536,
"maxBlockHeaderSize": 1100,
"minFeeA": 44,
"minFeeB": 155381,
"minUTxOValue": 1000000,
"poolDeposit": 500000000,
"minPoolCost": 340000000,
"keyDeposit": 2000000,
"nOpt": 150,
"rho": 0.003,
"tau": 0.20,
"a0": 0.3
},
"genDelegs": {
"42d339844d4593edc456d1c80b256fa57e9b4b4dccda5b587ea7a958": {
"delegate": "53465dff1bf47517a5b354888b32972647d208cac07907aa8efa5a03",
"vrf": "61e67274fe923060e82635768ec21e62846023804cc0f080c5c2b475151c2770"
},
"95dbfe2cf93a2db109863659c10dd5785201d71eb43ae4a264d2b731": {
"delegate": "2ca5c291c7f00776e8c6a2482198bb03ff90abd638dc650936739b8d",
"vrf": "7b6a8ba747c498db386227fe0747dba44197816d82bc662e92c32a00f0e4906e"
},
"28466494f218d24d9627c4ffcf55671f894f775ee782bfd61ca3a4e8": {
"delegate": "bd4a372503f35313c4f17e3cdc012f460119af1841c509c763218fc8",
"vrf": "4c6d14ca2697dd446d4963c99dcb2a02419052beaad3c9aa7e37c261c8138c94"
}
},
"updateQuorum": 3,
"networkId": "Mainnet",
"initialFunds": {},
"maxLovelaceSupply": 45000000000000000,
"networkMagic": 42,
"epochLength": 21600,
"systemStart": "2020-07-25T13:00:00Z",
"slotsPerKESPeriod": 7200,
"slotLength": 1,
"maxKESEvolutions": 62,
"securityParam": 108
}

View File

@ -0,0 +1,9 @@
{
"Producers": [
{
"addr": "relays-new.mainnet-candidate-4.dev.cardano.org",
"port": 3001,
"valency": 2
}
]
}

View File

@ -0,0 +1,3 @@
{
"Producers": []
}

2
cfg-templates/test/VARS Normal file
View File

@ -0,0 +1,2 @@
export NETWORK_ARGUMENT="--testnet-magic 1097911063"
export HARDFORK_EPOCH=1

View File

@ -0,0 +1,481 @@
{ "bootStakeholders":
{ "182822494f30b89a5cb9a6d845d9733a1831eb4e5ebc8faca89becc4": 1
, "37ec19ad6c732dea93f8b39e0dcbef7d45044983d99195eb7034901c": 1
, "3c1c3b43032f1f7a346cb8070c75474715ec8f1d301411a69def9ab2": 1
, "6275f793595cae0761f13ecd054a0f01d0f57726ade0933e88a05749": 1
, "9a804607ce670b2d5e60e9b4fdc54b99acf6d66837132e6bdc621ba5": 1
, "9bfb38ba283fb3c8e552b440c17d0ef32725c39219565e9190454a57": 1
, "e471e138c71dfff3d326b75548a1c518e694d13e85a3b0ae91df9941": 1
}
, "heavyDelegation":
{ "9bfb38ba283fb3c8e552b440c17d0ef32725c39219565e9190454a57":
{ "omega": 0
, "issuerPk":
"y1HSmrlOUNmhRNT0JlZM7HAN7k2ehXqs+R07aJN02B90KkUoGM8kicFt/Bhvbpx2t99AhFt8RQeF8C2ICXZ1dQ=="
, "delegatePk":
"fsJJ2JDQqvmoEgeWDBY64tasXnFcprltWGDlDZ8rKyodVo+qh8nMi/1DOjIkqW7F0QG0tunbAI24hX9JuuKUsg=="
, "cert":
"a304bf45b44fbccc78f54b9014a6b2d4354631ebff235aebb2e71a15bdd582be3794384c1ba713b99ef05766e92b8f438b2fc5af349f2bb16e85e3780aa84c07"
}
, "37ec19ad6c732dea93f8b39e0dcbef7d45044983d99195eb7034901c":
{ "omega": 0
, "issuerPk":
"nw+fw9f3biUiBZVS6H4G2vlAtFgaF5rsd/OQVmKkGGWv2lr820QVemFc7G/xmtOZ2bAyjcgrx/NRPUCRC3+TSg=="
, "delegatePk":
"MqlUtSHAsZUUQIllgx72g5Y33noaYWi8+EVcUEupO5yFNJi9rgYKb8mUXXIxrgjRMXq7szMGyTRl5e8RjuvHGA=="
, "cert":
"3fbff2edf71960355b30d89b946d4732c88e66dfb859bb143d2cd368b923cdf7d9bd22c4901cb47bade479a7c0eda08470cc9f3a2cb20c92b3a20974fc066900"
}
, "9a804607ce670b2d5e60e9b4fdc54b99acf6d66837132e6bdc621ba5":
{ "omega": 0
, "issuerPk":
"KedfHXp2SA8aETBEmrXZoOAUwJiFDKFSA3gq3rdWGoG7Mid0F0kSWzK3C6Y8QDIvRnao1lfZpXmghht8L0wCcg=="
, "delegatePk":
"52SwNA17NT9fdFiRAzd05L6raqFFilT/KaEyTAW7mHa1dM9ZKg+G/dH7+vvt3p4izpUiWy8RhRYpOszYygswFg=="
, "cert":
"06682af4df67b2037337187f9397bb8042e37308da1429ec9063e42480f9da60379d929f705140f05f1d014f19c668071824c0d86b616794e544d935e379c80e"
}
, "182822494f30b89a5cb9a6d845d9733a1831eb4e5ebc8faca89becc4":
{ "omega": 0
, "issuerPk":
"U6JXlR27xStIbWOjpfzqVVy5rp73La1i5znqNsI94+xYpOzGmlOVYiYF88N5OZ82wDBtl1UB9A+bWXNa0oCapg=="
, "delegatePk":
"5bwhqDYWvMz+ND7Da53EwGyQ6RPfHYoLBGAIZR9CyqlKrob7/cRYbavVR6fpLQdwLjMrzJ5911MjncgNAzxZwg=="
, "cert":
"d173106bfaab665a30e71633719754e0416927cfdadd6fbf7013590ddc9843083e18efcd08e4c7c366f4c4fff257177c87a502913f35bb1a07e45607c5d1fa0a"
}
, "e471e138c71dfff3d326b75548a1c518e694d13e85a3b0ae91df9941":
{ "omega": 0
, "issuerPk":
"HISQWQHTy1IdXEM7sTpZDNIQO0alFI++YFE6sAD5lN1BNDzTDSzDfUeaoAVWBvT/L5LcHdRzsjRgnPcOOm28gg=="
, "delegatePk":
"T011I+QeBYpsve+1U4ZU/8KlNBan9buZ9+rGmdQtXB8TdXbpwo6fFLPG4IIS8jjYbW4BrPJpf3teR9qWOSZeMQ=="
, "cert":
"018a7ee167602da08bf7d6903c37d2524ebe2a5daad83f9bf25f6011622932e72fc7c48027b9d4efaef521c911ec9eebaa38ddf88e6ae27c9bb823770fcd2600"
}
, "3c1c3b43032f1f7a346cb8070c75474715ec8f1d301411a69def9ab2":
{ "omega": 0
, "issuerPk":
"276WEVFXba36w7tXnsKxwUfACqTO4Dx+vvSVoOo4KUCqBgPahpnaCca9yjIPzWhVC6iyrHkZ570z7VjF2drNRA=="
, "delegatePk":
"c65B7KK+N/wVxVpQ1mjIZH4QvyIhcsLVir+m6TEOWWI/jyb47cHOj2mL1dyf6qMay8Nkv/b7gdND/zgm692NVQ=="
, "cert":
"b2c8e6ff8fc380c4a4c4e16f909803e786ccfbf4267e5016e24a34a843093b4d81736939500fb6fdd358d2be2b255858ea1abc35f62d381d6c62d111d1f0c80d"
}
, "6275f793595cae0761f13ecd054a0f01d0f57726ade0933e88a05749":
{ "omega": 0
, "issuerPk":
"bO9W1q+IRfMXlJvN/5I1jxOU/hG0XAKyjh1YVMD6E/jgeWRN/FBBr7D8vR9H7HzgZPN7fsXAcMeEpWGeuuKqYA=="
, "delegatePk":
"37YVphVo1oZ/RahcMiJ/JwJRgNc4qKPX/TySn2JNcjkpgBs0NkHxSAh7EX6H6WlfIV28+DD/DVigZmgsdgP2QQ=="
, "cert":
"a9c6e4abf95755084a86625a98e185de75d4d33d557284d3aa67ecff3dcfd8e77994fc8b3fc4c2762879ca0c15458ade936db0977ae10dd01291cf3241b9530e"
}
}
, "startTime": 1563999616
, "vssCerts":
{ "60214fff2df8faabc7da2dc99c07d2e3ade761b6bfe6a5a94b44c3dc":
{ "vssKey": "WCECGkF8Ipu3QuaaTiSnA/wmf//wmVhFM2rIVUupnP9fdGM="
, "expiryEpoch": 3
, "signature":
"ff0972de56a180ae5a452680f7c6c464d07cd539804930b1d2f815b9a9bcc652c8d7adf875e4435ee116b16d194e35acfc752cc14c2e9c46bd00f74ec363a502"
, "signingKey":
"fsJJ2JDQqvmoEgeWDBY64tasXnFcprltWGDlDZ8rKyodVo+qh8nMi/1DOjIkqW7F0QG0tunbAI24hX9JuuKUsg=="
}
, "e0c9e75ffe8065e50563f9ec256c2b442a121d602c495cd305fb3cc4":
{ "vssKey": "WCEDBRKTUNRUx1VFORWuoqqMSwPYKXgkeO2e+LTbc8jxm7U="
, "expiryEpoch": 4
, "signature":
"4d0aa42d1a15decec74c117b9b3e76178155c58ec373d2535005b4a3b0fae0ca4dd1c089b5272036f642aea27dc835e91de73d12fc25c027a8ef73991c139407"
, "signingKey":
"5bwhqDYWvMz+ND7Da53EwGyQ6RPfHYoLBGAIZR9CyqlKrob7/cRYbavVR6fpLQdwLjMrzJ5911MjncgNAzxZwg=="
}
, "fe299fde9afe6467393772f49e1f8d646d6788400c0acffdfb5eea24":
{ "vssKey": "WCEDT9Z69y24Jbc4x/MlaC33mB/yaZ4ljIMNAfl9l7njWFE="
, "expiryEpoch": 1
, "signature":
"0efc47d2ed049a72896a4db314a3b00b31b849c753eaa2e3172337a8439a9160eba6bc164f57819df6580140fe3c7f52cec98161596c452d7ced3b0881638a09"
, "signingKey":
"MqlUtSHAsZUUQIllgx72g5Y33noaYWi8+EVcUEupO5yFNJi9rgYKb8mUXXIxrgjRMXq7szMGyTRl5e8RjuvHGA=="
}
, "837bd45aa9cdb656f538a4e46236ba9eb4c89890bc9191df096e30ba":
{ "vssKey": "WCEDKi5sm8Wu7tUrjSehtCBsEMXSpX+h87zNRJcE4Mx/Nj4="
, "expiryEpoch": 1
, "signature":
"991e11c37f235c8c8d4aa846a564da38027f739f34ab97087ab436cce84d9297b2951455d5a8e2a562ab11db6a321c36d7498de3a1f776ad8eeb4dc5293b2b0f"
, "signingKey":
"52SwNA17NT9fdFiRAzd05L6raqFFilT/KaEyTAW7mHa1dM9ZKg+G/dH7+vvt3p4izpUiWy8RhRYpOszYygswFg=="
}
, "304889400de0859e03daea8bcf42779a14540b7c067f42f04ee1284e":
{ "vssKey": "WCEDOgMx00aA40zA9oi0rN61TB6OxUcTvYq+8CyJjrObO3s="
, "expiryEpoch": 5
, "signature":
"10eca6d26d44eb52ed11ae633c410866bd6e01411ad64068331c7b8f92da9c8b9a7bed1772b6bf00910d322e659e23f2f867c4cf4e757cdbfbfb1fc97ba5a004"
, "signingKey":
"c65B7KK+N/wVxVpQ1mjIZH4QvyIhcsLVir+m6TEOWWI/jyb47cHOj2mL1dyf6qMay8Nkv/b7gdND/zgm692NVQ=="
}
, "73c89ad521f5786011201377e1ec8305e82aa985998f40307fa927d1":
{ "vssKey": "WCEDLPG8x46r/wCR3hoHLeS+h/1Bu5x0MWXHDoJhM++fEfw="
, "expiryEpoch": 2
, "signature":
"98b48773afad287dbcd25915ee6b297b09d1204feb3a5793e91e438a1cce31a226f28b0c5b5ccdcde6a11f64665cbd867213cadbc57ec722c242def811f6e806"
, "signingKey":
"37YVphVo1oZ/RahcMiJ/JwJRgNc4qKPX/TySn2JNcjkpgBs0NkHxSAh7EX6H6WlfIV28+DD/DVigZmgsdgP2QQ=="
}
, "06216081b85063b2c7e33172b87663511fb7be35b23bc383881d60bc":
{ "vssKey": "WCEDExIpntsz081SiKqeAg2o9W+wLy6lmD0dfp1sesQMj/E="
, "expiryEpoch": 5
, "signature":
"2b7fb3aab3a23d72cac699c4ef97d7f90ca4dd0b06c2413962b6430583b9814b6549806e90ecfd44da05819b655ff975797a6df23dde2aa1c625ab5079825f03"
, "signingKey":
"T011I+QeBYpsve+1U4ZU/8KlNBan9buZ9+rGmdQtXB8TdXbpwo6fFLPG4IIS8jjYbW4BrPJpf3teR9qWOSZeMQ=="
}
}
, "nonAvvmBalances":
{ "2cWKMJemoBajGgvgVVziaKmUFa4LwJnAHffmuaSJBMDqethwJVQsyBsTSfFhp5jFpkVQM":
"5428571428571429"
, "37btjrVyb4KEg6anTcJ9E4EAvYtNV9xXL6LNpA15YLhgvm9zJ1D2jwme574HikZ36rKdTwaUmpEicCoL1bDw4CtH5PNcFnTRGQNaFd5ai6Wvo6CZsi":
"19999999999999"
, "37btjrVyb4KCRtni6YrG77RLPosnDqtEYoAD5xLdKYkWgnLqGa8yuXDUQd3psHrfxqaRcvNTsAW4ngUe6bzstbzSUJtwoaKbYaL8zjFAJJsZkQ42ti":
"19999999999999"
, "37btjrVyb4KGDMix4Uj5opvbMDgjZYUjeARAqTEFEbgLUH3qyju9gkBpcm2fVWgkcNgK3xFsQgWm1w8zxqvm9P6xJj9mHqLeMJPwDMUKUGPcDyUaDS":
"19999999999999"
, "37btjrVyb4KEkSeCVx985rXc38DCud2AW4LdasNmyoPLbtDGcDCyYVdf8BzxvDnzPehv4kyVBkzThjVEkSpGTv8PGQs4yRUgiCaKa7PTtBY4ohNGqR":
"19999999999999"
, "37btjrVyb4KFGS7upvgJHtmp7y7EFB67utzaHf7PM8y8U4tNkpmARNwiD7seN4NSAceHmj64KLGgh9qn1BpYF49NyWxocBHn1N533qBUYfhQar9ceu":
"19999999999999"
, "37btjrVyb4KCfir7GrvC6Y5kBNjeakZNd5po62AzQQ85SGkBB4QfXibC4fSNK5YvNeVgmPc8WbEeSUHRjoiqhJ4HDtinK2deBHSdCH6Cw8k2u92rdh":
"19999999999999"
, "37btjrVyb4KGAExHTQjLUHJBksSXGTomjgNsw8a4KepCgQYk4gxacKb84vGpPSv9Pjt3gdgMjA1nB67Pq3XyJpTDk8kLcXpJawCe6SCJf5jUowvAz8":
"19999999999999"
, "37btjrVyb4KCE1qeEoUh9b8CpcZcJ794Di14AxAELGoppJNVdB79nnuKcgRut566MdDkxTqravFaDSD9iwAvDByUHi59xocCY3ButEjmCQeLTLZXQ7":
"19999999999999"
, "37btjrVyb4KGGSGD8KgQD6qUBaSjxy5JRtsmMSHEGGAZqA29ULGwci8TcM16vBhywuBw54izQtpAqXeyUnbjh56hCgoqGZp9tHTMLLkEgLzwxVCZ4N":
"19999999999999"
, "37btjrVyb4KG5ZZfwwiQuhAGWiNJ2FhXP3oAuiq75qknCz4CZWNMVY4B9BmiHRHnWfhUbkLHUqfabCYASUk2V1qGuDw97x1gdf871aFY7Lpz3N1NvT":
"19999999999999"
, "37btjrVyb4KFtDHT2vDtMvQbLBgfH5hnpyVTTqqpPsieykukuxrDShHNccAEEj7M87UuV2GJ5pPA7YJ4JPjSokA99XaDgLmeaAumhZPHMwzg2Laspr":
"19999999999999"
, "37btjrVyb4KDHFyvvKb29RD53ebt6N8kpbL41J4VxWpiFC4FnxxybP33M9tBbdqfMXvSvyTQpv4dULXf5B838kEWXSJ24bpHtFgcbRkiHQwqWFQ5du":
"19999999999999"
, "37btjrVyb4KFh7jhHCtWxW942ceq7Xhxay8FZ7GkEBezGyFm3wJcVBGy1YYJDZ4Z7GbrFZmHLSe47zFs8Rjxk8rveoRpo1s43HXrMrhd4ijim4jJVP":
"19999999999999"
, "37btjrVyb4KFhYgC9Lr4Se7C1gL39d5WBVADyUyQZz2BfG4BZxczyW827JRQR5enyWaoj6NnA5NyKsheV6Eb7WvQtbN8D6116HTknHhEb5jh1yUU6Z":
"19999999999999"
, "37btjrVyb4KDLtM8HUJsBwergjZUj4DcMfkFmbV4bXUFGJk815o9nowX9ndPPVAeSNjAFYqJeFwTiMa9Ka8LqBnqFZgPpacyx9LrQLoXVMjvvLB7DK":
"19999999999999"
, "37btjrVyb4KDec7E64byKc4XjmmCRDaTGQYgHJTPDijZVr7NwZSP8g7ienzTLx5Z1quaQRhJqqAyV8Z2QdkzXvjTTRiVDCqps78uGp3uuth4wEJKP9":
"19999999999999"
, "37btjrVyb4KF5R1LEsaQgjWFWXwbgJ51naDEaCRG23KiAN3UtGzaT5PvUANtFBgjmcCtPLMBYMTGL4S8px4HyQMLAyF4fakYoFAJC3PkxCWMUatGWD":
"19999999999999"
, "37btjrVyb4KFB5Tmw1wsLmuv17Q6y8i6HGpVxbW8k4bevmob3DcdbH6jzrAtUrBpKgfTGgPMpLAbJcpaByGGJErkXQWFwrNMW35S79hxFvAN2GTXVQ":
"19999999999999"
, "37btjrVyb4KDEX2XToMQoi1No3YdREgZWzrf1xQPbfhbZTZnprFwDsRMiBxqUrA7p4BwjxXHDyqAccPwyX8iWWquz2CrLazJMR4s8AMz2US1D1ffJL":
"19999999999999"
, "37btjrVyb4KFTKCoqtZBdbh7LtJ9mRR1nbkX7ggP6a7AwvkSDxUN6U5GJWfuRXnL3a5x5e16uQwyjC6PoPVQ7VLdJXr8Kd3eFknLu6NDf2ey4AaJo2":
"19999999999999"
, "37btjrVyb4KCHCpiGd1J2GtVjP4KxEWP7RE6K6yxHzE97cbDgFD63fUFygbni8jKw1N37nGsT43KBvBn5w9ee8sVegr6Tg8fAr52mUkhdvTZYJV52T":
"19999999999999"
, "37btjrVyb4KGLRpX3uQfSeLovpMTcWfVZSM5RCufYvy2tyCMwrLXyHKCM9VqQh8dCQA6WcTrViaxqpvBSeKreHFL4CftfJU1z7CjHAze236NLesbL8":
"19999999999999"
, "37btjrVyb4KEdwV1MS3Pjek1HjLN2CSq3SJZGFBbZctkGLz569i9RWN15bAvCcZ8R5dgEi8iYjpmMVKioufoGv3issZQvVtzPz38pWHBViyRK2how5":
"19999999999999"
, "37btjrVyb4KD1x4cqHfGxrvBubZ8pSM8Jmw15UiHpy77eMsqpMewGND2GdvAwTBZhf4KA4uypBJnuUPbPYFovpRVJ92BUaMBHfQnAD3i15DAzD8EvL":
"19999999999999"
, "2cWKMJemoBait15xg1M73WAvWafoieg2GrcykbRk6J1QC2jMUXn7LpXf4mk5RUeu8qYeG":
"5428571428571429"
, "37btjrVyb4KC3HyNR82Bj2Sr9o6CF9o3J5hBNycGb9JwrHggTYUHfivi87akkYDv8ayepMkM4mNvxTKvoVdMHFkMnZZgrk5qobwPKM8idSnYYmvTRU":
"19999999999999"
, "37btjrVyb4KCmCLYttFEWLNQc1MRbV1NyhhssRioZ5CgkqHgYUTT1pPSr2hrfevSe8bSwLiPsLnaCbsxJQc5SWgWYEJDPWuUA1s4AotQxERNbT9ReA":
"19999999999999"
, "2cWKMJemoBahLnFCQ8wrTuZ3sMyiCeEkUZDYLNucPiVTJr8UU3BgADsKtqosDYNFXzeiw":
"5428571428571429"
, "37btjrVyb4KDHDPBVenqrh8tUTVNYX5ZGwjd4r3svqdnwWicGnMZZV1E7nBJVQsDY69co936H9onHpmA3PYSabYH4ibbULphL1CitDgArH9KknBARc":
"19999999999999"
, "37btjrVyb4KD9Z53z9qD7gTWMHr22e8jDcpCHgJFQaGQsvnNkycRehAaxLAnufNRjhLzQ57XVGJnR6mcsk6MorapLpADT77tyTaX9xfUSZyTA32ZAy":
"19999999999999"
, "37btjrVyb4KCsozLcUUHR8GyVG7erY6j9zehKTADn3e5xpRJtu1YgfJzSmAyERBHUXa5LGWY2aR2KqcssnRjwugh1bGjxc6U6ZrePJnALYTw2TR3yh":
"19999999999999"
, "37btjrVyb4KEDBSAmNtUBy6pfXesvTvtrDZQsSYcyo7SUwjLkhoSaPDCsNqMmoGbqzFQyEe9DNwK59BMudtdkzFPBpbgiEWx5SZr6vVMbpe86qsQJV":
"19999999999999"
, "37btjrVyb4KFf5NQ1DuNoAP4phRomqdEUmtFb6sWcDHkizGj56dwn54LfKrfWa6Er5sxDXYrzpWwS56PKmKaBjJtn1JqN67K3CihFXXospn8B2TDz2":
"19999999999999"
, "37btjrVyb4KBPHxFJqCekpPztGnLgbVsUA46Q8Lj2LKbFJL5Nqk5LgP2u28eBJAxkkU2r118ARdXW7fXLPQgctwK22L4N3zc6XeoDqkadGmTd4s8a1":
"19999999999999"
, "37btjrVyb4KBYe4RSCngNCgVMAeMJkRQqoJs8t6t9e9BHcNvvT6awv4CruMWH2FyiudxcGfZHmjghDvqk39iFrmCt4XE2XDuYzyo97BxwS6MngfeWp":
"19999999999999"
, "37btjrVyb4KF3MxxJBeJqCPFgHyUsSDkrDqoctSSVi9h7F4Wj9zFKcPVuVju76KYhdp7nJhy44512Wjhw7WH4sed3MMSh1HYnKUfjZXGkoZXMajaye":
"19999999999999"
, "37btjrVyb4KDsi9fc3RfExWLumjkp2YrcMjZpew19Z92kZnjPy5Xa84KY2WZw6xmjJA7AXFJCBWtrF9RFw1BjCewEqK77CVYj2s7bk9aAA7yyZARRz":
"19999999999999"
, "2cWKMJemoBaj34AMeqLspGBgX1PVc7z6VkALK3rtVd8iFgCtMUenNoHhVRnjeGfYVQJM1":
"5428571428571429"
, "37btjrVyb4KDpppzxzoaPgnstPejNxGaSZ3Vh22Qd2DWGrwfLJ2tizs33Y5Yjya1U6TXPzVX2PT5g1PXMy4jR4aWZRGZqYJk4Uw9p1h6BhEa189eiN":
"19999999999999"
, "37btjrVyb4KEXaPVoMuKpnVEKKLMFuGSvYL7YMAD529yxeK8Y1zqnbh5FQ8GMYpJwARugWmzaXdJ1gopgsxziC4e5wgjf3zkp7RH41KTJ73xLyfrFP":
"19999999999999"
, "37btjrVyb4KBrhG1yaBVY3X1ZoTCjUH7gbiA4qSFsMGgtLUBgwHiMZPiAJ3kQrRiboPV3s7eYXZD9fnd27qRb1cCEMc4oU57aPn2cYcEdAEJHrsyLB":
"19999999999999"
, "37btjrVyb4KEC4vC63KNqRBD7RX1KBwWDdPDE6oXGxP8x5aKrbVTALaq4XBdak8F47Kt9VcsQvVsKZfAit8vBtZpG2mc6VKUXCFv8pTYWwQMnABckB":
"19999999999999"
, "37btjrVyb4KFPbetkmdvqD8nLRFsUVL4HsVUYmgaZhAmBXcr78M3XoZkptjuszd2T1FNr1fGZApkZFZXikGtyhCc7jH5JYD1q8csTNSWQn4Us3nzX9":
"19999999999999"
, "37btjrVyb4KDfwNJcNMYsyEDVHWrGrNAPBwF9FGEnm5j2XFs4BeGdiSPqPtqCjWCvcRYBfY5EoDjRBhjsTrr2HjB1jw8XZ9Hy8wd9gz4KkCbMugSgf":
"19999999999999"
, "37btjrVyb4KEgvmzjLT7R9xHg1vNob6vCf999UFuG4qfTpHGZufdhbkUogSFJXtQXnCcJDHJ6xuZt92H6VgxGdhSLQ9gmWZy4zCJEVu8Nj8NashVQY":
"19999999999999"
, "37btjrVyb4KAtY8hCobTmAB36dzosSo644ZrzATKQhP1AsnM6BAVfTWwMX5BGXhigxLm5hk4beodymyjivxrH7ZY6BZjMu3AtafB5guvagxEZM7vJq":
"19999999999999"
, "37btjrVyb4KCRMJDqQ3iK4M19XhWGWpFbCoxjgeDB7ZqUhgW7jSYLEk5oVL4okVPVx5rXCgoK2ND9kAWnNU5QncJp1qvuCngRdJaLrvFwp4boE56VR":
"19999999999999"
, "37btjrVyb4KBTRHUnz17FQNFzHR8PpoGGwuNQZauAUxmvTb1o7Ragv9Zvyiv6Cb3rnrmYY1PGtVFTmom3TGg4mK5XpkRyf7PnnCG5EQM69i7MViLpU":
"19999999999999"
, "2cWKMJemoBam1WPtZrz3Fi4EMUDao74k9Xn4fhyVYLqK4o1VRzoxPFU91QBRToLbVyrjX":
"5428571428571429"
, "37btjrVyb4KBUH8nDpwtt3sSc6rJ7AkYjmnqvt1tJ4J8ZKCuqPrEuEioJJZXeD9aohveoB9zhRWru6oM5zyBcgMtkA26HLtTDKsSVwzoqugfftbiPu":
"19999999999999"
, "37btjrVyb4KCgWqZ8sJW46mQGdZS9wKW2TEQesyCoRScUxvisbdvEkfsxYLR49i6wE6uP1BBgPX9eg8cxKHPuNyKpStwf5UVmRCXD2ahotjamotMwV":
"19999999999999"
, "37btjrVyb4KCR9vZcXetWv4QdP4jPSH4msGeXs8DUBUMVYJHgD62etfv2jiD7gmLbLezCAiGTQu9JvrHd9Wfu74wguKgkX1vCUQkzcWsn4rVWsKCyt":
"19999999999999"
, "37btjrVyb4KFV3TiBqtLDN3oHQr5NrA8ouAAqasFU4ZuB9W13xgcgWsSy5fUtbNL4imCruQz19hjzBzykxGxCAarrviCUBh3sxWbvvTTHdvpyWGgXc":
"19999999999999"
, "37btjrVyb4KGM5rFFreGtZAs4PFB2Drb37uXRHebh8rCeVWFkW8De8XAbYqvfQrAqVthfJp9Qy2YzbzNhWSiUGY3D7yJkRkChyMveKCWT8qUTNEu6e":
"19999999999999"
, "2cWKMJemoBahEJS9xuB3R1ofSgtG621enmfpxfx9Unpo2K26wJPioaA4tizZrNMACNoQb":
"5428571428571429"
, "37btjrVyb4KFGV8HUDv7S5E8CSBV3pQLgGFt5HXa2jb9ofbAo3gTxcaQ4So84mHsNk9mhAybq6miH2VZU3iz7cqCd74gPMyn3zdUsrF1u2rib7HSXq":
"19999999999999"
, "37btjrVyb4KCF4JTyyC27XuFmcrn9Nxj1DmM4G5BKnf8F8F8BSpvn3PnsLRNH2RZJoajmg4yqHnwMXpUnbb7sFSuthjXv6YUenX8EWsApQUzAm77Dm":
"19999999999999"
, "37btjrVyb4KD5zMmtnD3jWpX3TSJnZJ8jMzCFQHYa3HcHNXxdAnK5A88SiWncRpJQxesMDrYgzPHk7SnFNag5teaFELV6hE9opnJpJzMGpVicDDRX4":
"19999999999999"
, "37btjrVyb4KDTABtj2RScLVCLVyFhxcURYUZNVta8CghbH5Edz32XSP79NHc28QTkKLMNUBupRnJXs4zcZt8C2fiPFGZfgSBMqMGMidWc2zo9piRb4":
"19999999999999"
, "37btjrVyb4KCGn7x5G6obn9NPNoTuv25LrBcqK9wHCm3XbrhxqycSQrbPfsDxgDp2M8pqTjCk8cVEG2fRxWrTjfG4q71MtyMo6nt8WG11kJzdQQSNL":
"19999999999999"
, "37btjrVyb4KEhnv3cCqP8jzRBbwE5v6ymPkBjTexHCcCgYJarjHHaxipJvz4aaXc5Xmp5KXxnC3SoE1oqR8sdGHobyfsAqJy7DwejZWpkkoYD7LJsS":
"19999999999999"
, "37btjrVyb4KDvKgSbCTx1gwwZFGe5DZaXyGwTYGGnJNCQ9C61XP4n1pKFQtNbYEowGeRoKHCGUvuU8Ebz2vQwN7YhcJ9bSb5oNpAoCe8UxX5KK5C3e":
"19999999999999"
, "37btjrVyb4KB6yr5YozXGqSKemHyZfsgiRQFX3VdJBKx7waoSaScNWc2dNvhNp6HSnXMxUwDtBvicXDWdpoJ7cKLWAwqEYki5azdt1qDP4sHXh8XhJ":
"19999999999999"
, "37btjrVyb4KCqRLQRj8svdZGGLQDZGdXztzeC15Vvt6uZWg23QAdfL1dMc52dpc8jqKquWNj6xjyLnLciVnRxzEq1kiq54ssmc6h7V5xK1cqqKJWBT":
"19999999999999"
, "37btjrVyb4KEW3PG2LAJNwmok2H6i149HetvT6fYrPsqPGpUkucNkA4b5TQmv896EF44UmcCAXDycfxFB7GcVefBCgk9cZffVUdX3kri3i5TEqSjKm":
"19999999999999"
, "37btjrVyb4KDdgCo1a7URfpQVFoTJEUcn4LqWpAtCeLaW7NeGMJtecsahTJM7886BjLcnhU2CboLSUojCPcab3WNTmXFDrRMHMHdmWefCAyYA7QaaL":
"19999999999999"
, "37btjrVyb4KG5vwKTPpCSQ14a7Cv4TESosSVoFVRHsw1vHj7Tpb7N4j1U5dtFcY7L3MWsH9BJqQjU9NxwaHpbHCJAhmsLi2mC2BE8k8Rj7zcjiiVhR":
"19999999999999"
, "37btjrVyb4KAr171Hd3fu65bbtKxqwktHGwY9kNanPYGXQcFKA8d9Hp1RgLrxzU1AdJCJbJDByTnHdDmtA7pm985tKK8hr5JdHPXFfSvkkYZn3kb9G":
"19999999999999"
, "37btjrVyb4KEZWqFxGYhFuLE23i92B8BiLRwwFUdnjmM24KHCNuWik5dc6MJqz7GxupgKGK5zzbYSXJyA8DQVDszyFmJuoxgzPn2GSnfBoREZ82ZdF":
"19999999999999"
, "37btjrVyb4KDB6sZamEoJWYBLoDWucRdDtRXCuQvLCoVoHPNjrywJKDz8PQg65ZtLvYvREwAK9oLzGGb6UcdAf9zwQcFaKRRHhLzCZxwTsRDVyPkSy":
"19999999999999"
, "37btjrVyb4KDJc8Af5dfJY2jcFbtkofFL6qXBxWnk2kHzCE63qAQR9Ynnk1XkfUrcnBrN7EEyvxmUDEFdNFfZHzXKhmkSQht3b6Y5rHHmuFYYoKdZz":
"19999999999999"
, "37btjrVyb4KDjPpuxBuJM1Ma5NGBqriSEAcozZMqYkWEkoJ3GgR8MAy3Zeb8q5BvtsWGEpSFQ69znPuaX4kVCcnEiEMDp91A6EL8A5YM12cpYYogLm":
"19999999999999"
, "37btjrVyb4KDmCmpc6FutA3PbQmWxcsbzZsFEdMKhHxrJVtGkmaiWd18dKmiaRA6o4Y2sAjDwjFozKzNzQg3dp8CXVSPpWgDLAXaozoRyPanW7UM8B":
"19999999999999"
, "37btjrVyb4KCLfSBFhCBdrb72YBNJkKcDCqpdxf3k7iwJTj7M3txxiq3fcam7Nyi8sLcJNSfgnUrh8C7RKEMN5wWpku7HLdZqZVuPRjeihhgXmEpCe":
"19999999999999"
, "37btjrVyb4KF3ZQhHTvVH3L7jNYoZ3XWK6SWpqZKiu9AGz6qNtxoxhAmmJpenFMA6fedYDT3Lt7cihgc1q4pE2GJXvPuknAkjvESmPxhhzkBzuiRis":
"19999999999999"
, "37btjrVyb4KF9xNLdS47pRBLB8e8bQLuvrBiGJbnHPNCbKU4wrMerJztEtYJdHayvaoUEmJ1vc3aiq9Z3UgP83Y1b4rpiyrGeYjzQhhDgB6DW8sWJm":
"19999999999999"
, "37btjrVyb4KC4LdZLvrexUgAntpySomDAPVwdMEnz1cP9pZxsxZqVYzM6zPPWAhc7byfwsLdgW8GEMTuTUagYFAKEmYgaDmYxK7cHxtWJG3hiMHxVU":
"19999999999999"
, "37btjrVyb4KFfXPG5GDEc4tLyVUSepKD9GGXZcSuP1xtLLRQnQr4wSXawT62bSJsiPzS25kdADKh94V3iDksm9nq5fhV4jixCnpNjsn7k2hSkwrAUa":
"19999999999999"
, "37btjrVyb4KC1L9MsZ8htPomWp4FV4hULeBVT6jf3GGqmDcw3k9tPn6pnfqGTWowQDvqVr7BqtQ5rcQ7gc5z41qh9vyBV7Ds83bRsndDbTAwkEUJ21":
"19999999999999"
, "37btjrVyb4KBtLs3NwnoLkyVx9ZxSoQ7mQx2ZvzanG7PGWWdMA9ksXqZxakLxdj9MAPKw7eQoZJWHxJJCsd7MeWj7ujfXtPsthGhcURT3Hste4Kr4n":
"19999999999999"
, "37btjrVyb4KCaYYFDdnbHEdBzpDPcL5iH98AGF8J5avuweDHwKChDq9mBvLKVJS6F4YTuAVDigPjMnAcuYUJ2UUbvDPePFZBhLhBrFUKeauoKC8X5z":
"19999999999999"
, "37btjrVyb4KFfnmiGpxNSGQVMfmFpAFrEAEhZwGPQDutSHnZqQXPhcXxDNcbdoKiztyQHpTA3jSmVowZCxcaJMS1k1wu8U6nXTzejgh7wYZjycamU6":
"19999999999999"
, "37btjrVyb4KCTVE8b2UitH791rYrkSrHG9u449h6JHKotuPWRsdVZQfP1jXrs4ygSxAnG1rM5mGFM6cmUqA44e9fenjbVC1QFYyn3R4CaptVZypKgW":
"19999999999999"
, "37btjrVyb4KDaKs8A6CU8Lrzxpr3WNM1kDdd4CPe66TqSP2ehHexrAuZ3ykMmhkaUZEHUEiq78ELQx5vpSFGHXFKbyGgrWa8rokqamCV8bSKiqsqVt":
"19999999999999"
, "37btjrVyb4KCdPziHrv1QgXL5zMy3KYxr7zPqoRd96iz3LNrkWbobRmPswTpRKgCQEkZcEnipiNJ5UoULAc33mbR44MchdHT5vLNYT9sPxwzpgNUWj":
"19999999999999"
, "37btjrVyb4KGAZJWCpicgRkb9ijP3Jnv6y9EYvnpMqkPdBZ2d6fdnCa9C97HUmfHLWF846AKjViPvnY7MbSM8mTM3VDx5RazBFxA7C7mZ9CyM48AW9":
"19999999999999"
, "37btjrVyb4KFfgfRyETGNXNXm6gAxNpTQSxr6bM7T6yZE1ibiZBovxG52PioVmLRnPYxs4wYddAfgTH4mbmtLFnwuZYSBh2eNsdLdc6vWb4AdJNNym":
"19999999999999"
, "37btjrVyb4KBsV28Wce4x44WsTVoXa5s4zaBKALWXxMQ2MtfVgB8LJJW34QFpvjrxKmheLtpcLyVqaeu36oB6ZcgQPppFN4oqhdueoKBEpn8dfQUVF":
"19999999999999"
, "37btjrVyb4KBEKzyCGqao8GmErVER19oBH3L8xVNCSZs8tCVd53iV5FXZAZ7bNCT67bKoasGeiYZxEoDzGBsKxb4uJxStU1e9wkaPo6BxUEErZG7LD":
"19999999999999"
, "37btjrVyb4KCi8WRzrkFiE1AVYbSiXBzMRTuTLv8DAchfg4tPaDgHRuDN6m4dq4VkA17pkWwCoa2NmvNb5sGeU1ZkjcqFuYrWPK2C5a3TLBfx64uLs":
"19999999999999"
, "37btjrVyb4KDz8QGqk9LJ9kSsSd1zKgqfTuiTKbL92b4aDSXmRPyrFZp3VPEwhMyEmwCiSkpd7KQztirmU6CGwiphhiHoXbbZjkbfiHN5Mq1y7fmJM":
"19999999999999"
, "37btjrVyb4KEcCa8yc1d8Zrne1hRtedHQQGPbkRJcvHak2ygcCndPfSqWwb2L59ERxhtqsMJLdS1fPQPs2vcJcQCvB52tCm4rGCDwUmRG51PUzjSVh":
"19999999999999"
, "37btjrVyb4KEhvykuoQZKWdNKFgTrugRUSV66yr8GCXREuaX2PfVQJeuXS4h1bNP8SeUxHAG2J6RfK35YnsZj5qkWQCWV7tVYMVokU5bw9y8CcmqPy":
"19999999999999"
, "37btjrVyb4KDsFS7rbQjZQGX6Fz53u76NF2hF9iqRhfbx8ePmjJKCsv5rZV1hhtP6DHdKwLAf5zkVH9FE51xYuCvJzNppSn1tgExVQJpuTwKmyTekT":
"19999999999999"
, "37btjrVyb4KFtfVixJcJdD27YZfXfRM5diZFj4TEazkCAhF8KyztTbe67zQpBc1RTjruHNvefdJ9Jtr7u5rebR71tGrGtKioSSGKy2hMKd6GUVFkEg":
"19999999999999"
, "2cWKMJemoBaiXc4dYCHfDyvy3LcqPebJ8zfRJsZZoHDqik2SzK9Be73YQ5W9u5jEiMPXa":
"5428571428571429"
, "37btjrVyb4KFNpxUYvzqFKsRfRYJKHjEuFfgy6rpoGq29dcMrNhbKTvqNr719U282rp9PcnFonAENkUdv2nE36wZmyNkj8JVQJL1TLu25SKjGFNzVs":
"19999999999999"
, "37btjrVyb4KFYnqsKFfMwj4S3PcCxwxutoiUubHazLfw4wJc5bfrQgpNEpRnGCS2UUfzvMWRRV2vy4wzPKE7tshLS2YEW219R6QfAenXzktMoXCmuU":
"19999999999999"
, "37btjrVyb4KEbo96SLroMfZB11rEvztPswgdqC5ESkHXc4EaFdAhsDQ24vJK23XsjTJzpPS3ZcDWiHiFVtmp5wkJrcnRcMe74s88eTy8YLvLL7EBRj":
"19999999999999"
, "37btjrVyb4KBcyGa22cYKz3Xo9UnB2kzZg4nqVX863JCAvUd54ehdg94DWwnBasCv6sUdbKdh9t4tf48oaXokeoms1HDNuegsmRjVntHBX3Z2hnrV7":
"19999999999999"
, "37btjrVyb4KDHmdZ8ewhythkmGaUzLCwME5pGtWR7nPhE9nCjLMcKstQFyKq1vTSagA2BXtiopfGwtLq2e1jhUVKsw1Z8Me6XTmLm5C9MzRYCZCd3n":
"19999999999999"
, "37btjrVyb4KBGJtifVyePJjSHTno1XNBeTcqmSqEhyUznts9KGQTsvCd9Hq6zM2w29njvmJYCtWmNkUXvayfqyv7epN1awWkKK1WUFQKJsjtevSKz7":
"19999999999999"
, "37btjrVyb4KEwqVLa1yaRPdDUctf525DovPsxoXZfqNp26eXQnmTSFwY3Q3rgPsjRfTKHKtjFpxPy6XYvjzscccsZYfXSaL9MmgrKAaeQgQhCtoXih":
"19999999999999"
, "37btjrVyb4KDxRyqtP9nWyEd7sfzdB8Xgh2egCATJAVtvxM2LhKLp1ALCE714vMCsbQZ5SwvVgiAvmieJTkae865ycwU39JN4pgt27pqEuB8uvi947":
"19999999999999"
, "37btjrVyb4KDA9F68PUv9efaoQHTvacu98Dk6Zx3784ADx4SDnwMfDt3uRfJwqBELeVuis5UEqsf9u4zAD9YC82s6YNmQu43avWDqrQq9Z4hHkEVrL":
"19999999999999"
, "37btjrVyb4KCjschbSccsYGDJo1rVBjdVrpH27iRtc5h1q4XRqpQJTma1NA9t9t8PrTsJjFE7WzNCczJHQR1RGXW1jDNEiEqNa6xctAZ4ZBtXKHVtp":
"19999999999999"
}
, "blockVersionData":
{ "scriptVersion": 0
, "slotDuration": "20000"
, "maxBlockSize": "2000000"
, "maxHeaderSize": "2000"
, "maxTxSize": "65536"
, "maxProposalSize": "70000"
, "mpcThd": "20000000000000"
, "heavyDelThd": "300000000000"
, "updateVoteThd": "1000000000000"
, "updateProposalThd": "100000000000000"
, "updateImplicit": "10000"
, "softforkRule":
{ "initThd": "900000000000000"
, "minThd": "600000000000000"
, "thdDecrement": "50000000000000"
}
, "txFeePolicy":
{ "summand": "155381000000000" , "multiplier": "43946000000" }
, "unlockStakeEpoch": "18446744073709551615"
}
, "protocolConsts":
{ "k": 2160
, "protocolMagic": 1097911063
, "vssMaxTTL": 6
, "vssMinTTL": 2
}
, "avvmDistr":
{ "CWJf8Kl8Gp-DhcWKuhNRUU9P0_CVI2LmpR1MIMxVgGQ=": "20000000000000"
, "h48-GEVDKf_0_vGKzmGOuAOhhIm2uc0OEDSNwFayV28=": "20000000000000"
, "PO1Kz9bpAowfWD8u9Ial2OkmxDiw6bK_ICDPvuHshJM=": "20000000000000"
, "mqJXwreGLRzV9a--egcVvKN4hzIcNUULsXqcPWe3YXI=": "20000000000000"
, "ENoYC3dNAtKL-lvjCTZDVhQYmfyWVtI0GNbz4QKqVdY=": "20000000000000"
, "o0O4s8YkitBZPeZLVyjn8pjtpBoncr-H9mbtAJS_KfE=": "20000000000000"
, "1XEVfDyaheIAeQICkHlwmvEuY9A7E50hA1v_E_QB3Fg=": "20000000000000"
, "OKVfmKrrzY0-10uxl9IxlYA6CFWwOU1dN-NyUI0bobU=": "20000000000000"
, "LYOSBM00cdDToqHepveoat2SN6vdPntA0nSFXRch83Q=": "20000000000000"
, "3Z-Z3rLCxLt0C3KgagBq3wOXrfm68_zh2st5Bi6Covs=": "20000000000000"
, "VTx9H6wpJNMC-H-pThklJ9uCllwqXaU0WXHcVTEFAIU=": "20000000000000"
, "beyF5mz8icvrBvM-mvQzLfbnHCmxOOg8Z7kJs7nySZs=": "20000000000000"
, "rs_VPO7SNO2YlSY2N881xHFeBnW_Sn2o4uSfuGpq9cc=": "20000000000000"
, "5RZPTI9FoSvLmiXjKYtUdkrqoMg99tIw8k4enSB1qlQ=": "20000000000000"
, "QRBLXNJdJCVDjbwPvQmg_liOcYIWfvoKf7Ns5w_RDvU=": "20000000000000"
, "YG9mVGb_MAvTSdFgOUV8JbRBxnj3sPELZxQNVup_X18=": "20000000000000"
, "7dEmv0hdv1a7imviD3q3p9pFBFMC77Byx9oinyGwdIQ=": "20000000000000"
, "H_Qs3m89FGw8QxVTUGuPjdbOPQyP8vzcD8I37BkRAXY=": "20000000000000"
, "pa6NZ1j_bs8kezg23cUQiba3UyLxLiGDQfDXMQmuPSE=": "20000000000000"
, "Qi5VCXOUdP-U-Pd--boAii_-gwMpB0IRfibzxWEN53s=": "20000000000000"
, "cLJrI380JOISi9A14PYTRmClcxPNQS3_GIZdqcXC1JQ=": "20000000000000"
, "BVY8wsqEPXPQ7DPTvnvat7GRiwxFPHC4jY1x3ZvY1PE=": "20000000000000"
, "FBlBD9ykcwuFmoogsVjRCUag9xpkwCAgbYDNazT1oY4=": "20000000000000"
, "KHwUZRYdwRs5UYIhOO9ycjucY8WvTzpkZgZ4PSbDDPI=": "20000000000000"
, "ED2RmO7Wfad2p4gxyzhr4gqlhavksgHEg1acZiKMQF4=": "20000000000000"
, "BOjqPWCmGewTKqKekH0HSgpnOEYT8g0qV4t4t6Nj7-c=": "20000000000000"
, "b-8mgbBV-r9bqufItyyPp2WLitNhBjaMAajl3GfteeE=": "20000000000000"
, "JW_kuEdd0TkJEUA35YUbf_K9C4OlpZd83iTUqrD0q0g=": "20000000000000"
, "IF7PMOFaXdwztrj1j_yx_YBafdZpb3pc5EF6y822KgI=": "20000000000000"
, "r9HNGwms9l0cMBuT8CznPoadXKbzLPceo4-vDydXUwE=": "20000000000000"
, "rM0RFpsVm738CCDdzBhrEz8Q0CLIqiBKMl5rtdFlWmA=": "20000000000000"
, "jFyHtgHVcd70V1SZ7O55mo8yvYw5KsijV6fMQEWkJaE=": "20000000000000"
, "qWmtDqvA3KZyySJLRPFPO2TiOZh3Dpv1FCJTdEilJvc=": "20000000000000"
, "5YYkqAleNp8VXGYiD7WsXvWZQwybkqAUR9xMf5lLvzs=": "20000000000000"
, "bi2YeYdi2W2r7IDYToq_N0RR1k3z4GYsRo2xddi2Y7I=": "20000000000000"
, "vENWfzLRm1wwHYWTUIOznVCXC3ISPt8J6n3gYFrwfpg=": "20000000000000"
, "G71fGc7_2IoExvY8VctjxMCd7lJsTWgvWzg__lF4qcY=": "20000000000000"
, "pFzX1lvX3LPolGCv8TQXfWAZupMZEjVlMWmT7nUV70I=": "20000000000000"
, "pE7umM4kIaTYqKOviWvgTb34xky-kpbN7VvSzhOT8wo=": "20000000000000"
, "P6J7kBAlCPD4wxAnzuzlqTBWMyqI1zVkqVWM5kKoCwg=": "20000000000000"
, "CmwjLeSIEKfLzd5ks16QoGCtYNc--wiGsgWWM4OKsco=": "20000000000000"
, "-RTrh8sxu9mOYYpcfmyod8-v1Z0nqxMunwK-_NFDzYQ=": "20000000000000"
, "EnoSKFBfSJ_l7RXMglXTSolDt6VeNRMay4soxkUmk0E=": "20000000000000"
, "VzxlTAQWmOH7ALIXviuXH2pjjYmtW77r9ypeEZlg4mc=": "20000000000000"
, "93QRpWUE-Yqthy85Y8poB_WeWdG8A_9nnq4HJiMfJQc=": "20000000000000"
, "H7YIN-FF0kUawzVnhQpCoMLuOJkLzYAtZ2xof7vhtPs=": "20000000000000"
, "a9_Q5Pzte2G7wXujwVBaAzLcMki6_UjKrxvWzayJ3gY=": "20000000000000"
, "O4h-7y-2Izq3ojxailZAbMd0VCq78-kIMv8gIcaA6cA=": "20000000000000"
, "mlzqpS0hE6s7apMGRQP4Cx5Fc380yt9gQX7XVcVrmQQ=": "20000000000000"
, "aK-WCeAwKHQE9H02zvRLRdoMPIsZWiOfKkbA6yTyMxs=": "20000000000000"
, "b3fq65eebunM4fM3AQubawjF6Mt9v9jyEXF5f3hewbo=": "20000000000000"
, "ZbZ7v6OcrjZ3vqPFVzaHOK2A5UzRYy-wm0C-ngebU_s=": "20000000000000"
, "zXza46kY7Gs5cJEoN2TUwAaXth5W7uUKQfNiaPyWDSc=": "20000000000000"
, "5q5RzTcpFFUne5AKkua3DJO1IFQEOGyb2jQvV4DmDT8=": "20000000000000"
, "5CzeQFC__uUi8TRPuWVgsUeJauYR3i1f3rvD0CrC34o=": "20000000000000"
, "KOp96-E17RXmCf0_vEOcecpTmY8W0wpbpBwFuPwFbKM=": "20000000000000"
, "EFK3F4mO823aCcko3QmFJ3Klm7glGs8a0f_f6WVIwdg=": "20000000000000"
, "e4TOcy9Qp5BQ8tXkEXaWpuHRmAVcJRfPEV3sVCOKZsQ=": "20000000000000"
, "w-2bM_wksghmtHp4ZB2ZOQ-V9Dw1ZivS7RwxgY-DsB4=": "20000000000000"
, "9pKGBzQJLoqY6vcOM_OqHRgq9KIdO3ovCBp1mBEFKek=": "20000000000000"
, "TMFEEMjP7q64-Liae7CEG0ELKtEC2e2vDuCpMItyfzU=": "20000000000000"
, "nrRREQUC1zKTpQRRNDzO-NiQh6DJahitvTk0SWLkc8g=": "20000000000000"
, "9xnVxPVNI9fdN5zGa5Fa3HcIwof5T-2lMbdLh3_Nbpk=": "20000000000000"
, "NqOaYkD2B5yTFQ1dHMY7X2LmV0Q9tZI6KYR1-dFW_z8=": "20000000000000"
, "zhXX6D5r4CDjlLLQiC87LZZL2zWUIYaXhxbcgq_Ww3w=": "20000000000000"
, "CXMg_ROxPjiJAyxUpBlUepLDhcdhMffR89izVr9vcRU=": "20000000000000"
, "vfTTtqpmg_3jQ7zWV3XhNfmtbtn32Z0fcfNc6_Cx-4E=": "20000000000000"
, "3UAwyThFcR1vKSBpktCSkJg3NpMQhL1z4l46NHpfJkY=": "20000000000000"
, "K4m8Vu1qtFRavgx0jrctVErZf6VbKDfBnigjQef6k-o=": "20000000000000"
, "rmyqI_SuwRsbR4rG1Uk6bUlSJRvo004w5SeejGQERT4=": "20000000000000"
, "oo8sxwl7TO2JP-QfW3_aQbE9zZCLBogFPnwEMPUBuYs=": "20000000000000"
, "lif3znin9EWfZBoYZ9Ta1c69eINSJNmaqkKJVpFuF2U=": "20000000000000"
, "kMAvVvgk0sEf3kHXyfb8gQ6H4gWaFBDSUwms4IFs2jo=": "20000000000000"
, "8CMex0Km9bk2J1r4FaSD_FSwlGRgh1e8C1-7fCGUAJE=": "20000000000000"
, "pUliJY_tq41pTdo5VJISdWbGGBnL_82pupm4AjZF-y0=": "20000000000000"
, "E7dg9_nI8tY9CXli9OyIHtx0FUsq0QZKLBVx9Cr8Daw=": "20000000000000"
, "cpO_GBP5qVwOCGxws6oGvgZszu7jy_LwbKZj_f2pg8o=": "20000000000000"
, "n8MZ16U_jB4Vg4BPZHGorDzVO7dC9qOfAdYhAluKD4Y=": "20000000000000"
, "hqzkwiRusxDSgY-MyqmCyTC0VxELSFdJKJVpzBGOdQM=": "20000000000000"
, "QCiQStlI-PWCbwclsM8ZvfrmP49kql7lAwJjgzZ_OvI=": "20000000000000"
, "7prDyNFRXierLX1UE26h-TSO0fmfC2lFHQoelogU3hg=": "20000000000000"
, "32mL1n7cF_xLIjWAGTC6vISGcafcJe0EgXaxaQNtrzQ=": "20000000000000"
, "H94Fk3T5fiEXPd1eGYfpwPP4_y9FVQWsi2bhIAf9hFE=": "20000000000000"
, "YLQqBDTjfVrQJcqCzgn0js4ScjJpbh3_dGRmg_wQ9WM=": "20000000000000"
, "Ctfg-00LO1JetbfqwOOIwrm56xdZSzzZRccGW52eCps=": "20000000000000"
, "GCkRs5Iqi5jyzRhF-Z5B4-EzgCRAb55pJK8a3kmrbwU=": "20000000000000"
, "975KNlfAi1B-u2Q0X0qBZpuZNLCUNnKnX-jvBzah3pE=": "20000000000000"
, "SrxXeNRxF0accD3dsKoj8ymSQeJoUVs78Llsy-4ZIO0=": "20000000000000"
, "m5zF99P2vG3cqGrG17VvRti7d2XRi3fuUHfec-jM6tQ=": "20000000000000"
, "A-w4r_kJIZpI8TqDAY-F44cR0lhZtnB25UhT0NXM6Zc=": "20000000000000"
, "7mglsAKSgUEkAyA6C5Ni-v_1xoGNPCN_cj7ctQZGZqg=": "20000000000000"
, "x3DrzZ_Yp8df2EGsGlwNAnclV2Tv3lcdqnI3Lk_0bF4=": "20000000000000"
, "GWoauU1tVb37fjs6mPrxXiBoy9HarPqyGI8zj1mc7cw=": "20000000000000"
, "op9p-7Xy9fBmzrjLbMD1jEuW1QVXTOsXSIwgaFN3sDk=": "20000000000000"
, "KC7yE_m_JSiWGVP9cpcfYTLF77taAPTgveRKEiIPg1A=": "20000000000000"
, "6V6sxoH3dMLw8vWcH0NQF2SZNPDzmtULTX4vxkeCQd4=": "20000000000000"
, "y0DLZDhvfU-M5MvdhoyxEFp811PWFfrAdIfDVhYCMzE=": "20000000000000"
, "wCHhA7PS7wdfEuMpzrOJfdGyF2uIChR2LnnAcQE3hHI=": "20000000000000"
, "s4iYnscFXdEK56b7o4ZvKpgN0YoKchpR-U9MZEqbGb8=": "20000000000000"
, "WkMPzKKtocKcbc7_fsFND1oln6gAfWJspg9REi75pMw=": "20000000000000"
}
, "ftsSeed":
"76617361206f7061736120736b6f766f726f64612047677572646120626f726f64612070726f766f6461"
}

View File

@ -0,0 +1,169 @@
{
"ApplicationName": "cardano-sl",
"ApplicationVersion": 0,
"ByronGenesisFile": "testnet-byron-genesis.json",
"ByronGenesisHash": "96fceff972c2c06bd3bb5243c39215333be6d56aaf4823073dca31afe5038471",
"LastKnownBlockVersion-Alt": 0,
"LastKnownBlockVersion-Major": 2,
"LastKnownBlockVersion-Minor": 0,
"MaxKnownMajorProtocolVersion": 2,
"Protocol": "Cardano",
"RequiresNetworkMagic": "RequiresMagic",
"ShelleyGenesisFile": "testnet-shelley-genesis.json",
"ShelleyGenesisHash": "9f9afb65aa682b19ff484a00baf7e21dcea965d85f72da85957b8405fd78b41c",
"TraceBlockFetchClient": false,
"TraceBlockFetchDecisions": false,
"TraceBlockFetchProtocol": false,
"TraceBlockFetchProtocolSerialised": false,
"TraceBlockFetchServer": false,
"TraceChainDb": true,
"TraceChainSyncBlockServer": false,
"TraceChainSyncClient": false,
"TraceChainSyncHeaderServer": false,
"TraceChainSyncProtocol": false,
"TraceDNSResolver": true,
"TraceDNSSubscription": true,
"TraceErrorPolicy": true,
"TraceForge": true,
"TraceHandshake": false,
"TraceIpSubscription": true,
"TraceLocalChainSyncProtocol": false,
"TraceLocalErrorPolicy": true,
"TraceLocalHandshake": false,
"TraceLocalTxSubmissionProtocol": false,
"TraceLocalTxSubmissionServer": false,
"TraceMempool": true,
"TraceMux": false,
"TraceTxInbound": false,
"TraceTxOutbound": false,
"TraceTxSubmissionProtocol": false,
"TracingVerbosity": "NormalVerbosity",
"TurnOnLogMetrics": true,
"TurnOnLogging": true,
"ViewMode": "SimpleView",
"defaultBackends": [
"KatipBK"
],
"defaultScribes": [
[
"StdoutSK",
"stdout"
]
],
"hasEKG": 12788,
"hasPrometheus": [
"127.0.0.1",
12798
],
"minSeverity": "Info",
"options": {
"mapBackends": {
"cardano.node-metrics": [
"EKGViewBK",
{
"kind": "UserDefinedBK",
"name": "LiveViewBackend"
}
],
"cardano.node.BlockFetchDecision.peers": [
"EKGViewBK",
{
"kind": "UserDefinedBK",
"name": "LiveViewBackend"
}
],
"cardano.node.ChainDB.metrics": [
"EKGViewBK",
{
"kind": "UserDefinedBK",
"name": "LiveViewBackend"
}
],
"cardano.node.Forge.metrics": [
"EKGViewBK"
],
"cardano.node.metrics": [
"EKGViewBK",
{
"kind": "UserDefinedBK",
"name": "LiveViewBackend"
}
]
},
"mapSubtrace": {
"#ekgview": {
"contents": [
[
{
"contents": "cardano.epoch-validation.benchmark",
"tag": "Contains"
},
[
{
"contents": ".monoclock.basic.",
"tag": "Contains"
}
]
],
[
{
"contents": "cardano.epoch-validation.benchmark",
"tag": "Contains"
},
[
{
"contents": "diff.RTS.cpuNs.timed.",
"tag": "Contains"
}
]
],
[
{
"contents": "#ekgview.#aggregation.cardano.epoch-validation.benchmark",
"tag": "StartsWith"
},
[
{
"contents": "diff.RTS.gcNum.timed.",
"tag": "Contains"
}
]
]
],
"subtrace": "FilterTrace"
},
"benchmark": {
"contents": [
"GhcRtsStats",
"MonotonicClock"
],
"subtrace": "ObservableTrace"
},
"cardano.epoch-validation.utxo-stats": {
"subtrace": "NoTrace"
},
"cardano.node-metrics": {
"subtrace": "Neutral"
},
"cardano.node.metrics": {
"subtrace": "Neutral"
}
}
},
"rotation": {
"rpKeepFilesNum": 10,
"rpLogLimitBytes": 5000000,
"rpMaxAgeHours": 24
},
"setupBackends": [
"KatipBK"
],
"setupScribes": [
{
"scFormat": "ScText",
"scKind": "StdoutSK",
"scName": "stdout",
"scRotation": null
}
]
}

View File

@ -0,0 +1,68 @@
{
"activeSlotsCoeff": 0.05,
"protocolParams": {
"protocolVersion": {
"minor": 0,
"major": 2
},
"decentralisationParam": 1,
"eMax": 18,
"extraEntropy": {
"tag": "NeutralNonce"
},
"maxTxSize": 16384,
"maxBlockBodySize": 65536,
"maxBlockHeaderSize": 1100,
"minFeeA": 44,
"minFeeB": 155381,
"minUTxOValue": 1000000,
"poolDeposit": 500000000,
"minPoolCost": 340000000,
"keyDeposit": 2000000,
"nOpt": 150,
"rho": 0.003,
"tau": 0.20,
"a0": 0.3
},
"genDelegs": {
"2f56e87d67b8e5216582cfeb95dbdc9083110a3ef68faaa51bef3a80": {
"delegate": "bd5933d3c5417f17a64c7214711a26abc3bc03e2c90dc1bb38e0c39f",
"vrf": "9a0b0f537874d089cedfa9e250150405e47ea29acee87c40a223ae0a175d26f8"
},
"514e81afb082fce01678809eebd90eda4f7918354ec7d0433ad16274": {
"delegate": "eff1b5b26e65b791d6f236c7c0264012bd1696759d22bdb4dd0f6f56",
"vrf": "e6f70fb10c7523aa76648e20d17e65fd9b2ed53960fbd20b308f223b703f2e23"
},
"2fca486b4d8f1a0432f5bf18ef473ee4294c795a1a32e3132bc6b90f": {
"delegate": "de665a71064706f946030505eae950583f08c316f0f58997961092b1",
"vrf": "c3fde629add60e30142cd7ef3c680610975208b08aee42203a5c40ad5992e8f6"
},
"4ee98623920698b77c1c7f77288cbdac5f9011ff8970b1f507567d0d": {
"delegate": "bf07107c6f632de95e34af7e009d2aafa19916c7ba89b944fbedcd72",
"vrf": "9d7d12e3d6b02835be3e76cfc6ae93d937035ee0e006d04a0eef9dea19754e21"
},
"0d06d2547ed371fdf95fb5c4c735eecdd53e6a5bb831561bd0fcfd3d": {
"delegate": "6df3e1b4b8a84c63c805076a85e5aa00924997a4eae85fddf0aee3ca",
"vrf": "0774e5810fe02a014ec97ef424797172f2b8c5dcfb6e4cfc98b411c31d5096d8"
},
"581e23030b6038bae716e5d64b9e053db10541b12e6b0b4eff485454": {
"delegate": "b0dca078b823cde627da136200d6618c49ad712b77972a1c5e135763",
"vrf": "16a4e883b72ddbd09a4f8a1170fc346ab11e4202f814faa73e9d2433ee03e7b0"
},
"e5f27655371b54aed91cc916b2569060978be80056768fee2cc5ce1b": {
"delegate": "b3873a254459f506e47b9a252ee7912e538b364447f31576a170db65",
"vrf": "cc5c897fdf5db0017326656fe35aeb20c72b175540793f9b9b8dc9ade001bbc4"
}
},
"updateQuorum": 5,
"networkId": "Testnet",
"initialFunds": {},
"maxLovelaceSupply": 45000000000000000,
"networkMagic": 1097911063,
"epochLength": 432000,
"systemStart": "2019-07-22T20:20:16Z",
"slotsPerKESPeriod": 129600,
"slotLength": 1,
"maxKESEvolutions": 62,
"securityParam": 2160
}

View File

@ -0,0 +1,9 @@
{
"Producers": [
{
"addr": "relays-new.cardano-testnet.iohkdev.io",
"port": 3001,
"valency": 2
}
]
}

View File

@ -0,0 +1,3 @@
{
"Producers": []
}

View File

@ -0,0 +1,2 @@
# Best Practice example
Running on the mainnet-candidate4 for testing purposes.

View File

@ -0,0 +1,14 @@
#!/bin/bash
docker network create -d bridge cardano
docker run -it --rm \
--name mc4-block-producing \
--network=cardano \
-e CARDANO_NETWORK="mc4" \
-e HOST_ADDR="0.0.0.0" \
-e NODE_PORT="3000" \
-e NODE_NAME="block-producing" \
-e NODE_TOPOLOGY="<IP-address of relay node>:3001/1" \
-v $PWD/config/:/config/ \
arradev/cardano-node:latest --cold-register --start --staking

View File

@ -0,0 +1,17 @@
#!/bin/bash
docker network create -d bridge cardano
docker run -it --rm \
--name mc4-cold-create \
--network=cardano \
-e CARDANO_NETWORK="mc4" \
-e NODE_NAME="cold-create" \
-e POOL_PLEDGE="100000000000" \
-e POOL_COST="1000000000" \
-e POOL_MARGIN="0.05" \
-e METADATA_URL="<URL of metadata.json>" \
-e PUBLIC_RELAY_IP="<Public IP-address of relay node>" \
-e PUBLIC_RELAY_PORT="3000" \
-v $PWD/config/:/config/ \
arradev/cardano-node:latest --cold-create

View File

@ -0,0 +1,18 @@
#!/bin/bash
docker network create -d bridge cardano
docker run -it --rm \
--network=cardano \
--name mc4-relay1 \
-p 3001:3001 \
-p 12798:12798 \
-e HOST_ADDR="0.0.0.0" \
-e NODE_PORT="3001" \
-e NODE_NAME="relay1" \
-e NODE_TOPOLOGY="<IP-address of relay node>:3000/1" \
-e NODE_RELAY="True" \
-e CARDANO_NETWORK="mc4" \
-e PROMETHEUS_PORT="12798" \
-v $PWD/config/:/config/ \
arradev/cardano-node:latest --start

View File

@ -0,0 +1,16 @@
#!/bin/bash
docker network create -d bridge cardano
docker run -it --rm \
--network=cardano \
--name main-producing \
-p 3000:3000 \
-p 12798:12798 \
-e HOST_ADDR="0.0.0.0" \
-e NODE_PORT="3000" \
-e NODE_NAME="block-producing" \
-e NODE_TOPOLOGY="<IP-address of relay1 node>:3000/1" \
-e CARDANO_NETWORK="main" \
-e PROMETHEUS_PORT="12798" \
-v $PWD/config/:/config/ \
arradev/cardano-node:latest --start --staking

View File

@ -0,0 +1,17 @@
#!/bin/bash
docker network create -d bridge cardano
docker run -it --rm \
--name main-registration \
--network=cardano \
-e NODE_PORT="3000" \
-e NODE_NAME="registration" \
-e NODE_TOPOLOGY="<IP-address of relay1 node>:3000/1" \
-e CARDANO_NETWORK="main" \
-e CREATE_STAKEPOOL="True" \
-e POOL_PLEDGE="100000000000" \
-e POOL_COST="340000000" \
-e POOL_MARGIN="0.05" \
-e METADATA_URL="<URL of metadata.json>" \
-v $PWD/config/:/config/ \
arradev/cardano-node:latest --start --staking

18
examples/main-relay1.sh Normal file
View File

@ -0,0 +1,18 @@
#!/bin/bash
docker network create -d bridge cardano
docker run -it \
--restart=unless-stopped \
--network=cardano \
--name main-relay1 \
-p 3000:3000 \
-p 12798:12798 \
-e HOST_ADDR="0.0.0.0" \
-e NODE_PORT="3000" \
-e NODE_NAME="relay1" \
-e NODE_TOPOLOGY="<IP-address of block-producing node>:3000/1" \
-e NODE_RELAY="True" \
-e CARDANO_NETWORK="main" \
-e PROMETHEUS_PORT="12798" \
-v $PWD/config/:/config/ \
arradev/cardano-node:latest --start

6
examples/metadata.json Normal file
View File

@ -0,0 +1,6 @@
{
"name": "Example Pool",
"description": "Cardano stakepool example",
"ticker": "TEST",
"homepage": "https://github.com/abracadaniel/cardano-node-docker"
}

View File

@ -0,0 +1,49 @@
version: "3.3"
services:
mc4-producing: # block-producing node
image: arradev/cardano-node:latest
stdin_open: true # docker run -i
tty: true # docker run -t
container_name: mc4-producing
network_mode: host
volumes:
- $PWD/config/local/:/config
environment:
- HOST_ADDR=0.0.0.0
- NODE_PORT=3000
- NODE_NAME=mc4-block-producing
- NODE_TOPOLOGY=127.0.0.1:3001/1
- NODE_RELAY=False
- CARDANO_NETWORK=mc4
- EKG_PORT=12888
- PROMETHEUS_PORT=12898
- PROMETHEUS_HOST=127.0.0.1
- POOL_PLEDGE=100000000000
- POOL_COST=1000000000
- POOL_MARGIN=0.05
- CREATE_STAKEPOOL=True
- METADATA_URL=https://gist.githubusercontent.com/abracadaniel/58dfa2cfe0f986c7f445deb151ed1b49/raw/4bb8155af7be65d7e9869f0923c7ce778c75368b/metadata.json
- PUBLIC_RELAY_IP=PUBLIC
command: --start
restart: unless-stopped
mc4-relay1: # relay node
image: arradev/cardano-node:latest
stdin_open: true # docker run -i
tty: true # docker run -t
container_name: mc4-relay1
network_mode: host
volumes:
- $PWD/config/local/:/config
environment:
- HOST_ADDR=0.0.0.0
- NODE_PORT=3001
- NODE_NAME=mc4-relay1
- NODE_TOPOLOGY=127.0.0.1:3000/1
- NODE_RELAY=True
- CARDANO_NETWORK=mc4
- EKG_PORT=12889
- PROMETHEUS_PORT=12899
- PROMETHEUS_HOST=127.0.0.1
- AUTO_TOPOLOGY=False
command: --start
restart: unless-stopped

5
monitoring/README.md Normal file
View File

@ -0,0 +1,5 @@
# Work in progress
See
https://docs.cardano.org/projects/cardano-node/en/latest/logging-monitoring/prometheus.html
https://docs.cardano.org/projects/cardano-node/en/latest/logging-monitoring/grafana.html

View File

@ -0,0 +1,15 @@
FROM nginx:alpine
LABEL maintainer="dro@arrakis.it"
EXPOSE 9091
ENV PROMETHEUS_HOST="prometheus" \
USER="" \
PASSWORD=""
RUN apk add --no-cache apache2-utils
RUN mkdir -p /config/
ADD nginx.tmpl.conf /nginx.tmpl.conf
ADD entrypoint.sh entrypoint.sh
ENTRYPOINT [ "/entrypoint.sh" ]

View File

@ -0,0 +1,7 @@
# prometheus-nginx proxy
For securing the prometheus endpoint by adding a nginx reverse proxy with basic auth and tls encryption
See
https://prometheus.io/docs/guides/tls-encryption/
https://prometheus.io/docs/guides/basic-auth/

View File

@ -0,0 +1,3 @@
#!/bin/bash
docker build -t arrakis/nginx-prometheus .

View File

@ -0,0 +1,14 @@
#!/bin/sh
# Init config
echo "Generating config"
cp /nginx.tmpl.conf /config/nginx.conf
sed -i "s/\[PROMETHEUS_HOST\]/${PROMETHEUS_HOST}/g" /config/nginx.conf
cat /config/nginx.conf
echo ""
# Generate password
htpasswd -b -c /config/htpasswd ${USER} ${PASSWORD}
echo "Starting nginx"
nginx -g "daemon off;" -c /config/nginx.conf

View File

@ -0,0 +1,32 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
server {
listen 9091;
location / {
auth_basic "Prometheus";
auth_basic_user_file /config/htpasswd;
proxy_pass http://[PROMETHEUS_HOST]:9090/;
}
}
}

View File

@ -0,0 +1,15 @@
FROM prom/prometheus:latest
LABEL maintainer="dro@arrakis.it"
EXPOSE 9090
#alias/host:port
ENV TARGETS="relay1/relay1:12798,producing1/producing1:12798"
USER root
ADD config.tmpl.yml /config.tmpl.yml
ADD entrypoint.sh /entrypoint.sh
RUN chmod 755 /entrypoint.sh
RUN mkdir /config/
ENTRYPOINT ["/entrypoint.sh"]

View File

@ -0,0 +1,6 @@
# cardano-node prometheus
To connect to and scrape data from the prometheus services in the cardano-nodes.
## Environment Variables
TARGETS="ALIAS1/IP:PORT,ALIAS2/IP:PORT"

View File

@ -0,0 +1,3 @@
#!/bin/bash
docker build -t arrakis/cardano-prometheus .

View File

@ -0,0 +1,22 @@
global:
scrape_interval: 15s # By default, scrape targets every 15 seconds.
# Attach these labels to any time series or alerts when communicating with
# external systems (federation, remote storage, Alertmanager).
external_labels:
monitor: 'codelab-monitor'
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
# The job name is added as a label job=<job_name> to any timeseries scraped from this config.
- job_name: 'prometheus'
# Override the global default and scrape targets from this job every 5 seconds.
scrape_interval: 5s
static_configs:
- targets: ['[NODE_HOST]:[NODE_PORT]']
labels:
alias: '[NODE_ALIAS]'
type: 'cardano-node'

View File

@ -0,0 +1,18 @@
global:
external_labels:
monitor: codelab-monitor
scrape_interval: 15s
scrape_configs:
- job_name: prometheus
scrape_interval: 5s
static_configs:
- labels:
alias: relay1
type: cardano-node
targets:
- relay1:12798
- labels:
alias: producing1
type: cardano-node
targets:
- producing1:12798

View File

@ -0,0 +1,9 @@
#!/bin/sh
# Init config
mkdir -p /config/
if [ ! -f "/config/config.yml" ]; then
python /init_config.py /config.tmpl.yml /config/config.yml
fi
prometheus --config.file=/config/config.yml --storage.tsdb.path=/config/data/

View File

@ -0,0 +1,35 @@
import os
import yaml
import sys
def parse_targets(targets_str):
if not targets_str: return None
output = []
targets = targets_str.split(',')
for target in targets:
alias, host = target.split('/')
addr, port = host.split(':')
output.append({
'targets': ['%s:%s' % (addr, port)],
'labels': {
'alias': alias,
'type': 'cardano-node'
}
})
return output
in_file = sys.argv[1]
out_file = sys.argv[2]
targets = parse_targets(os.environ.get('TARGETS'))
if targets:
with open(in_file) as file:
config = yaml.full_load(file)
print(config)
print(targets)
config['scrape_configs'][0]['static_configs'] = targets
with open(out_file, 'w') as _file:
documents = yaml.dump(config, _file)

View File

@ -0,0 +1 @@
pyyaml

41
scripts/cold_create Normal file
View File

@ -0,0 +1,41 @@
#!/bin/bash
source /scripts/init_node_vars
export WAIT_FOR_SYNC=False
echo "Creating Stake Pool addresses, keys and certificates, to be submitted to the blockchain."
# If staking/ directory exists create a backup
if [ -d "${NODE_PATH}/staking/" ]; then
TIMESTAMP=$(date +%s)
BACKUPNAME="staking.${TIMESTAMP}.tar.gz"
echo "staking directory already exists."
echo "Backing up to ${BACKUPNAME}."
mkdir -p ${NODE_PATH}/backups/
tar -zcvf ${NODE_PATH}/backups/${BACKUPNAME} ${NODE_PATH}/staking/ > /dev/null
fi
# Start creation
generate_wallet owner
register_stake_address owner --cold-create
tar -zcvf wallets-hot.tar.gz --exclude='*.skey' staking/wallets/
## Generate wallets for multiple owners
if [ -n "$MULTI_OWNERS" ]; then
for i in $(echo ${MULTI_OWNERS} | sed "s/,/ /g")
do
generate_wallet $i
register_stake_address $i --cold-create
done
fi
generate_operational_certificate
generate_registration_certificates --cold-create
register_stake_pool --cold-create
echo "Archiving required files"
cd ${NODE_PATH} && tar -zcvf staking-hot.tar.gz --exclude='cold-keys' --exclude='wallets/*/*.skey' staking/
echo "Created all addresses, certificates and transactions. Upload the \`staking-hot.tar.gz\` file to your live node, and submit the registration transaction by running with the \`--cold-register\`."
read

110
scripts/cold_register Normal file
View File

@ -0,0 +1,110 @@
#!/bin/bash
source /scripts/init_node_vars
source /scripts/functions/check_address_registration
source /scripts/functions/wait_for_address_registration
source /scripts/functions/wait_for_pool_registration
source /scripts/functions/wait_for_slot
source /scripts/functions/wait_for_sync
if [ -f "${NODE_PATH}/staking/POOL_VARS" ]; then
source ${NODE_PATH}/staking/POOL_VARS
if [ -n "${REGISTERED_COLD}" ]; then
echo "Registration is already done."
exit
fi
fi
function submit_stake_addr {
WALLET=$1
cd ${NODE_PATH}/staking/wallets/${WALLET}/
STAKE_ADDR=$(cat stake.addr)
echo "Submitting stake address for wallet ${WALLET}"
if [ -n "$(check_address_registration ${STAKE_ADDR})" ]; then
echo "Your stake address for ${WALLET} has already been registered in the blockchain."
return
fi
OUT=$(cardano-cli shelley transaction submit \
--tx-file transactions/register_stake_address.signed \
${NETWORK_ARGUMENT} 2>&1)
if [[ $OUT =~ "Error" ]]
then
echo "An error occoured."
echo ${OUT}
read
exit
else
echo "Transaction has been submitted to the blockchain."
echo ${OUT}
echo "Wait for the blockchain to register the address."
wait_for_address_registration ${STAKE_ADDR}
echo "Your stake address is now registered in the blockchain."
touch transactions/register_stake_address.submitted
fi
}
# Check for staking-hot.tar.gz
if [ ! -f "${NODE_PATH}/staking-hot.tar.gz" ]; then
echo "Missing required ${NODE_PATH}staking-hot.tar.gz file. First run with the \`--cold-register\` argument on a secure offline node."
read -n 1 -r -s -p "If you already have generated the file, please place it in its correct place, and press ENTER to continue."
fi
# Backup staking/ directory
if [ -d "${NODE_PATH}/staking/" ]; then
TIMESTAMP=$(date +%s)
BACKUPNAME="staking.${TIMESTAMP}.tar.gz"
echo "staking directory already exists."
echo "Backing up to ${BACKUPNAME}."
mkdir -p ${NODE_PATH}/backups/
tar -zcvf ${NODE_PATH}/backups/${BACKUPNAME} ${NODE_PATH}/staking/ > /dev/null
fi
# Unpack staking-hot.tar.gz
cd ${NODE_PATH} && tar -xvf staking-hot.tar.gz
source ${NODE_PATH}/staking/POOL_VARS
# Wait for node to sync
if [[ "${WAIT_FOR_SYNC}" == "True" ]]; then
wait_for_sync 99.90
fi
# Submit the stake address transaction
submit_stake_addr owner
if [ -n "$MULTI_OWNERS" ]; then
for i in $(echo ${MULTI_OWNERS} | sed "s/,/ /g")
do
submit_stake_addr $i
done
fi
# Submit the pool transaction
read -n 1 -r -s -p $'Press enter to submit the stake pool registration transaction...\n'
echo "Submitting transaction"
OUT=$(cardano-cli shelley transaction submit \
--tx-file cold-registration/register_stake_pool.signed \
${NETWORK_ARGUMENT} 2>&1)
if [[ $OUT =~ "Error" ]]
then
echo "An error occoured."
echo ${OUT}
read
exit
else
echo "Transaction has been submitted to the blockchain."
echo ${OUT}
echo "Wait for blockchain to register the pool"
wait_for_pool_registration
echo "Your stake pool registration has been sent to the blockchain."
fi
echo "Press any key to continue."
echo "export REGISTERED_COLD=True" >> ${NODE_PATH}/staking/POOL_VARS
read

35
scripts/create_stakepool Normal file
View File

@ -0,0 +1,35 @@
#!/bin/bash
# We run a syncing node which is needed to query the blockchain for creating and registering the keys and certificates.
# Then synchronously we start creating and registering the keys.
mkdir -p ${NODE_PATH}/logs/
for i in "$@"; do
case $i in
--cold-create)
COLD_CREATE=1
break
;;
--cold-register)
COLD_REGISTER=1
break
;;
*)
break
;;
esac
done
if [ -n "$COLD_CREATE" ]; then
cold_create |& tee ${NODE_PATH}/logs/create_stakepool.$(date +%s).log
elif [ -n "$COLD_REGISTER" ]; then
tmux \
new-session "source /scripts/functions/run_node; run_node" \; \
split-window "cold_register |& tee ${NODE_PATH}/logs/register_stakepool.$(date +%s).log" \; \
select-layout even-horizontal
else
tmux \
new-session "source /scripts/functions/run_node; run_node" \; \
split-window "source /scripts/functions/create_and_register_pool; create_and_register_pool |& tee ${NODE_PATH}/logs/create_stakepool.$(date +%s).log" \; \
select-layout even-horizontal
fi

View File

@ -0,0 +1,10 @@
function auto_topology_start {
# Add topology_submit to crontab
echo "Starting crontab."
cp /cfg-templates/crontab /crontab
service cron start
crontab /crontab
# Update topology.json
topology_update 1
}

View File

@ -0,0 +1,6 @@
function check_address_registration {
source /scripts/init_node_vars
STAKE_ADDR=$1
cardano-cli query stake-address-info --address ${STAKE_ADDR} ${NETWORK_ARGUMENT} --allegra-era | grep -v {}
}

View File

@ -0,0 +1,58 @@
function check_balance {
PRICE=$1
if [ -z "$COLD_CREATE" ]; then
while true; do
echo ""
echo "Checking balance for address ${ADDRESS}."
echo ""
TOTAL_LOVELACE=0
cardano-cli query utxo ${NETWORK_ARGUMENT} --allegra-era --address ${ADDRESS}
UTXOS=$(cardano-cli query utxo ${NETWORK_ARGUMENT} --allegra-era --address ${ADDRESS} | tail -n +3)
echo "UTXO#TXIX: LOVELACE"
while IFS= read -r line ; do
arr=(${line})
LOVELACE=${arr[2]}
TOTAL_LOVELACE=$(expr ${TOTAL_LOVELACE} + ${LOVELACE})
if [ -n "${LOVELACE}" ]; then
echo "${arr[0]}#${arr[1]}: ${arr[2]}"
if [ "$LOVELACE" -ge "$PRICE" ]; then
UTXO=${arr[0]}
TXIX=${arr[1]}
LOVELACE_FOR_UTXO_TXIX=$LOVELACE
fi
fi
done <<< "${UTXOS}"
if [ -n "${UTXO}" ]; then
LOVELACE=$LOVELACE_FOR_UTXO_TXIX
echo "Address is successfully funded."
echo ""
echo "Got UTXO"
echo "UTXO: ${UTXO}#${TXIX}"
echo "Lovelace Holding: ${LOVELACE}"
break
fi
echo "You need to fund your address with atleast ${PRICE} Lovelace to continue with the transaction."
echo "Your payment address is:"
echo "${ADDRESS}"
echo ""
echo "If you have funded your address, you need to wait for the transaction to be processed and your node to synchronize."
sync_status
echo ""
sleep 10
done
else
echo "Find UTXO and TXIX containing atleast ${PRICE} Lovelace for address ${ADDRESS} (Wallet ${WALLET})"
echo "Run \`cardano-cli query utxo ${NETWORK_ARGUMENT} --allegra-era --address ${ADDRESS}\`, on online node to find the values."
read -p "Enter the UTXO: " UTXO
read -p "Enter the TXIX: " TXIX
LOVELACE=0
fi
}

View File

@ -0,0 +1,13 @@
function check_kes_status {
source /scripts/init_node_vars
source ${NODE_PATH}/staking/pool-keys/KESPERIOD
if [ -n "$EXPIRESLOT" ]; then
CURRENT_SLOT=$(get_slot)
SLOTS_LEFT=$(expr ${EXPIRESLOT} - ${CURRENT_SLOT})
echo ${SLOTS_LEFT}
else
echo 0
fi
}

View File

@ -0,0 +1,6 @@
function check_pool_registration {
source /scripts/init_node_vars
POOL_ID=$(cat ${NODE_PATH}/staking/POOL_ID)
cardano-cli query ledger-state --allegra-era ${NETWORK_ARGUMENT} | grep publicKey | grep ${POOL_ID}
}

View File

@ -0,0 +1,39 @@
function create_and_register_pool {
source /scripts/init_node_vars
source /scripts/functions/wait_for_socket
echo "Creating Stake Pool addresses, keys and certificates, and submits to the blockchain."
# If staking/ directory exists create a backup
if [ -d "${NODE_PATH}/staking/" ]; then
TIMESTAMP=$(date +%s)
BACKUPNAME="staking.${TIMESTAMP}.tar.gz"
echo "staking directory already exists."
echo "Backing up to ${BACKUPNAME}."
mkdir -p backups/
tar -zcvf ${NODE_PATH}/backups/${BACKUPNAME} ${NODE_PATH}/staking/ > /dev/null
fi
# Wait for database to load (wait_for_socket in loop)
wait_for_socket
# Start creation
generate_wallet owner
register_stake_address owner
## Generate wallets for multiple owners
if [ -n "$MULTI_OWNERS" ]; then
for i in $(echo ${MULTI_OWNERS} | sed "s/,/ /g")
do
generate_wallet $i
register_stake_address $i
done
fi
generate_operational_certificate LIVE
generate_registration_certificates
register_stake_pool
# Stop syncing cardano-node so block-producing node can be started
killall -9 cardano-node
}

View File

@ -0,0 +1,10 @@
#!/bin/bash
GENESIS=${NODE_PATH}/shelley-genesis.json
startTimeGenesis=$(cat ${GENESIS} | jq -r .systemStart)
startTimeSec=$(date --date=${startTimeGenesis} +%s) #in seconds (UTC)
currentTimeSec=$(date -u +%s) #in seconds (UTC)
epochLength=$(cat ${GENESIS} | jq -r .epochLength)
currentEPOCH=$(( (${currentTimeSec}-${startTimeSec}) / ${epochLength} )) #returns a integer number, we like that
echo ${currentEPOCH}

View File

@ -0,0 +1,7 @@
#!/bin/bash
# Init vars
source /scripts/init_node_vars
BLOCK=$(cardano-cli query tip ${NETWORK_ARGUMENT} | jq -r '.blockNo')
echo "${BLOCK}"

View File

@ -0,0 +1,6 @@
#!/bin/bash
# Init vars
source /scripts/init_node_vars
cardano-cli query protocol-parameters ${NETWORK_ARGUMENT} --allegra-era --out-file protocol.json

View File

@ -0,0 +1,3 @@
function get_public_ip {
echo $(dig TXT +short o-o.myaddr.l.google.com @ns1.google.com | awk -F'"' '{ print $2}')
}

View File

@ -0,0 +1,7 @@
#!/bin/bash
# Init vars
source /scripts/init_node_vars
SLOT=$(cardano-cli query tip ${NETWORK_ARGUMENT} | jq -r '.slotNo')
echo "${SLOT}"

View File

@ -0,0 +1,3 @@
function init_config {
python3 /scripts/init_config.py
}

View File

@ -0,0 +1,20 @@
function node_info {
STAKEPOOL=$1
if [ -n "$STAKEPOOL" ]; then
POOL_ID=$(cat ${NODE_PATH}/staking/POOL_ID)
source ${NODE_PATH}/staking/POOL_VARS
source /scripts/functions/stakepool_info
echo "Pool ID: ${POOL_ID}"
stakepool_info
fi
echo "Node name: ${NODE_NAME}"
echo "Network: ${CARDANO_NETWORK}"
echo "Host Address: ${HOST_ADDR}"
echo "Public IP: ${PUBLIC_IP}"
echo "Node Port: ${NODE_PORT}"
echo "Node path: ${NODE_PATH}"
echo "EKG Port: ${EKG_PORT}"
echo "Prometheus Port: ${PROMETHEUS_PORT}"
}

View File

@ -0,0 +1,17 @@
function run_node {
source /scripts/init_node_vars
source /scripts/functions/node_info
# Running in loop allows for restarting without restarting the container
while true; do
echo "Starting cardano-node"
node_info
cardano-node run \
--topology ${NODE_PATH}/topology.json \
--database-path ${NODE_PATH}/db \
--socket-path ${CARDANO_NODE_SOCKET_PATH} \
--host-addr ${HOST_ADDR} \
--port ${NODE_PORT} \
--config ${NODE_PATH}/config.json
done
}

View File

@ -0,0 +1,21 @@
function run_stakingnode {
source /scripts/init_node_vars
source /scripts/functions/node_info
echo "Starting cardano-node as a staking node."
node_info 1
# Running in loop allows for restarting without restarting the container
while true; do
cardano-node run \
--topology ${NODE_PATH}/topology.json \
--database-path ${NODE_PATH}/db \
--socket-path ${CARDANO_NODE_SOCKET_PATH} \
--host-addr ${HOST_ADDR} \
--port ${NODE_PORT} \
--config ${NODE_PATH}/config.json \
--shelley-kes-key ${NODE_PATH}/staking/pool-keys/kes.skey \
--shelley-vrf-key ${NODE_PATH}/staking/pool-keys/vrf.skey \
--shelley-operational-certificate ${NODE_PATH}/staking/pool-keys/node.cert
done
}

View File

@ -0,0 +1,19 @@
function stakepool_info {
if [ -f "${NODE_PATH}/staking/metadata.json" ]; then
METADATA=${NODE_PATH}/staking/metadata.json
POOL_NAME=$(jq -r '.name' $METADATA)
POOL_DESCRIPTION=$(jq -r '.description' $METADATA)
POOL_TICKER=$(jq -r '.ticker' $METADATA)
POOL_HOMEPAGE=$(jq -r '.homepage' $METADATA)
echo "Pool Name: ${POOL_NAME}"
echo "Pool Description: ${POOL_DESCRIPTION}"
echo "Pool Ticker: ${POOL_TICKER}"
echo "Pool Homepage: ${POOL_HOMEPAGE}"
fi
echo "Pool Pledge: ${POOL_PLEDGE}"
echo "Pool Cost: ${POOL_COST}"
echo "Pool Margin: ${POOL_MARGIN}"
}

16
scripts/functions/status Normal file
View File

@ -0,0 +1,16 @@
function status {
source /scripts/functions/wait_for_socket
source /scripts/functions/check_kes_status
wait_for_socket
while true; do
KES_SLOTS_LEFT=$(check_kes_status)
echo "Your KES and VRF keys and node certificate has to be renewed in ${KES_SLOTS_LEFT} slots."
echo "To renew run \`generate_operational_certificate\`"
echo ""
echo "Node sync status:"
sync_status
sleep 60
done
}

View File

@ -0,0 +1,26 @@
#!/bin/bash
# Thanks to Smaug from https://t.me/CardanoStakePoolWorkgroup
source /scripts/functions/wait_for_socket
wait_for_socket
GENESIS=${NODE_PATH}/shelley-genesis.json
BYRON_GENESIS=${NODE_PATH}/byron-genesis.json
#HARDFORK_EPOCH=208 # Defines the epoch which the hardfork happened in. 1 for MC4, 208 for mainnet. This is set in the network VARS file
NETWORK="${NETWORK_ARGUMENT}" # replace by --mainnet for mainnet
epoch_length=$(jq -r .epochLength $GENESIS)
slot_length=$(jq -r .slotLength $GENESIS)
byron_slot_length=$(( $(jq -r .blockVersionData.slotDuration $BYRON_GENESIS) / 1000 ))
byron_epoch_length=$(( $(jq -r .protocolConsts.k $BYRON_GENESIS) * 10 ))
byron_start=$(jq -r .startTime $BYRON_GENESIS)
byron_end=$((byron_start + HARDFORK_EPOCH * byron_epoch_length * byron_slot_length))
byron_slots=$(($HARDFORK_EPOCH * byron_epoch_length))
now=$(date +'%s')
expected_slot=$((byron_slots + (now - byron_end) / slot_length))
current_slot=$(cardano-cli query tip $NETWORK | jq -r '.slotNo')
percent=$(echo -e "scale=2\n$current_slot * 100 / $expected_slot" | bc)
echo "slot ${current_slot}/${expected_slot} ${percent}%"

View File

@ -0,0 +1,27 @@
#!/bin/bash
source /scripts/functions/get_public_ip
source /scripts/functions/wait_for_sync
echo "Submitting IP to topology updater."
# Wait for node to sync
if [[ "${WAIT_FOR_SYNC}" == "True" ]]; then
wait_for_sync 99.98
fi
cd ${NODE_PATH}
mkdir -p ${NODE_PATH}/logs/
NWMAGIC=$(jq -r .networkMagic < ${NODE_PATH}/shelley-genesis.json)
TIMESTAMP=$(date +%s)
BLOCK=$(get_block)
PUBLIC_IP=$(get_public_ip)
echo "Network Magic: ${NWMAGIC}"
echo "Block: ${BLOCK}"
echo "IP: ${PUBLIC_IP}"
echo "Port: ${NODE_PORT}"
echo "Submitting..."
curl -s "https://api.clio.one/htopology/v1/?port=${NODE_PORT}&blockNo=${BLOCK}&valency=1&magic=${NWMAGIC}${T_HOSTNAME}" | tee -a ${NODE_PATH}/logs/update_topology.${TIMESTAMP}.json

View File

@ -0,0 +1,35 @@
#!/bin/bash
source /scripts/functions/get_public_ip
cd ${NODE_PATH}
echo "Updating topology.json using topology updater."
RETRY=$1
NWMAGIC=$(jq -r .networkMagic < ${NODE_PATH}/shelley-genesis.json)
CUSTOM_PEERS=$(python3 /scripts/get_topology_str.py)
curl -s -o ${NODE_PATH}/topology.auto.json "https://api.clio.one/htopology/v1/fetch/?max=14&magic=${NWMAGIC}&customPeers=${CUSTOM_PEERS}"
PRODUCERS=$(jq -r .Producers < ${NODE_PATH}/topology.auto.json)
if [[ "${PRODUCERS}" == "null" ]]; then
echo "Update of topology.json was unsuccessful."
cat ${NODE_PATH}/topology.auto.json
if [[ -n "$RETRY" ]]; then
echo "Submitting IP to topology updater database and retrying fetching the topology."
topology_submit
topology_update
fi
else
# Replace topology
mv ${NODE_PATH}/topology.json ${NODE_PATH}/topology.backup.json
mv -f ${NODE_PATH}/topology.auto.json ${NODE_PATH}/topology.json
# Restart cardano-node
echo "Restarting cardano-node"
killall -9 cardano-node
read
fi

View File

@ -0,0 +1,13 @@
function wait_for_address_registration {
source /scripts/functions/check_address_registration
STAKE_ADDR=$1
echo "Waiting for the blockchain to register the address."
while true; do
if [ -n "$(check_address_registration ${STAKE_ADDR})" ]; then
break
fi
echo "Blockchain has not yet registered the address. Waiting.."
sleep 10
done
}

View File

@ -0,0 +1,5 @@
function wait_for_file {
FILE=$1
while [ ! -f ${FILE} ]; do sleep 1; done
}

View File

@ -0,0 +1,12 @@
function wait_for_pool_registration {
source /scripts/functions/check_pool_registration
echo "Waiting for the blockchain to register the pool."
while true; do
if [ -n "$(check_pool_registration)" ]; then
break
fi
echo "Blockchain has not yet registered the pool. Waiting.."
sleep 10
done
}

View File

@ -0,0 +1,15 @@
function wait_for_slot {
WAIT_FOR_SLOT=$1
echo "Waiting for slot ${WAIT_FOR_SLOT}"
while true; do
SLOT=$(get_slot)
if [ "$SLOT" -ge "$WAIT_FOR_SLOT" ]; then
echo "Reached slot ${WAIT_FOR_SLOT}"
break
fi
echo "Slot: ${SLOT}/${WAIT_FOR_SLOT}"
sleep 10
done
}

View File

@ -0,0 +1,17 @@
function wait_for_socket {
source /scripts/init_node_vars
while true; do
OUT=$(get_slot)
if [[ -z "$OUT" ]]; then
echo ""
echo "Waiting for cardano-node to read the blockchain and start the socket. May take a while."
echo "Trying again..."
sleep 10
else
echo "Socket to node is functional."
break
fi
done
}

View File

@ -0,0 +1,16 @@
function wait_for_sync {
source /scripts/functions/wait_for_socket
wait_for_socket
WAIT_FOR_SYNC=$1
echo "Waiting for node to sync to atleast ${WAIT_FOR_SYNC}%"
while true; do
SYNC_PCT=$(sync_status | tr ' ' '\n' | tail -1 | sed 's/%//g' | bc)
sync_status
if [[ (($SYNC_PCT > $WAIT_FOR_SYNC)) ]]; then
echo "Reached ${SYNC_PCT}%"
break
fi
sleep 10
done
}

View File

@ -0,0 +1,111 @@
#!/bin/bash
# From Documentation
# https://github.com/input-output-hk/cardano-tutorials/blob/master/node-setup/060_node_keys.md
# https://github.com/input-output-hk/cardano-tutorials/blob/master/node-setup/080_register_stakepool.md
# Init vars
source /scripts/init_node_vars
source /scripts/functions/wait_for_sync
# Enter staking directory
mkdir -p ${NODE_PATH}/staking/pool-keys
mkdir -p ${NODE_PATH}/staking/cold-keys
cd ${NODE_PATH}/staking/
echo ""
echo "Generate operational certificates"
if [ -d "pool-keys/" ]; then
source pool-keys/KESPERIOD
BACKUPNAME=pool-keys.$(date +%s).tar.gz
echo "pool-keys already exist."
echo "Created at slot: ${KESSLOT}"
echo "Backing up to ${BACKUPNAME} before creating new KES keys."
mkdir -p ../backups/
tar -zcvf ../backups/${BACKUPNAME} pool-keys/ > /dev/null
fi
if [ -d "cold-keys/" ]; then
BACKUPNAME=cold-keys.$(date +%s).tar.gz
echo "Backing up to ${BACKUPNAME} before creating new KES keys."
mkdir -p ../backups/
tar -zcvf ../backups/${BACKUPNAME} cold-keys/ > /dev/null
fi
# Create cold key
if [ ! -f "cold-keys/cold.skey" ]; then
echo "Creating cold keys."
echo "Warning: The cold keys should NOT be kept on your server. You should backup your cold keys and delete them from the server."
echo "Alternatively you can generate the keys on a seperate offline node, and move all the neccessary certificates and keys to the active staking node."
cardano-cli node key-gen \
--cold-verification-key-file cold-keys/cold.vkey \
--cold-signing-key-file cold-keys/cold.skey \
--operational-certificate-issue-counter-file cold-keys/cold.counter
cardano-cli stake-pool id --verification-key-file cold-keys/cold.vkey > ${NODE_PATH}/staking/POOL_ID
else
echo "Cold keys already exists."
fi
# Create Verifiable Random Function key
if [ ! -f "pool-keys/vrf.vkey" ]; then
echo "Generating VRF key"
cardano-cli node key-gen-VRF \
--verification-key-file pool-keys/vrf.vkey \
--signing-key-file pool-keys/vrf.skey
fi
# Create Key Evolving Signature key
if [ ! -f "pool-keys/kes.vkey" ]; then
echo "Generating KES key"
cardano-cli node key-gen-KES \
--verification-key-file pool-keys/kes.vkey \
--signing-key-file pool-keys/kes.skey
fi
# Get tip
TIP=$1
if [ -z "$TIP" ]; then
echo "You need to find the current tip of the blockchain. To get the current tip you can run the command \`get_slot\` in the your relay container."
read -p "Enter the current tip slot: " TIP
elif [ "$TIP" == "LIVE" ]; then
echo "Getting slot from live socket"
if [[ "${WAIT_FOR_SYNC}" == "True" ]]; then
wait_for_sync 99.90
fi
TIP=$(get_slot)
fi
# Get KESPeriod
SLOTSPERKESPERIOD=$(jq -r '.slotsPerKESPeriod' ${NODE_PATH}/shelley-genesis.json)
MAXKESEVOLUTIONS=$(jq -r '.maxKESEvolutions' ${NODE_PATH}/shelley-genesis.json)
MAXKESSLOTS=$(expr ${SLOTSPERKESPERIOD} \* ${MAXKESEVOLUTIONS})
KESPERIOD=$(expr ${TIP} / ${SLOTSPERKESPERIOD})
#KESPERIOD=$(expr ${KESPERIOD} - 1) # Because of bug in 1.19.0
EXPIRESLOT=$(expr ${TIP} + ${MAXKESSLOTS})
echo "export SLOTSPERKESPERIOD=${SLOTSPERKESPERIOD}" > pool-keys/KESPERIOD
echo "export KESSLOT=${TIP}" >> pool-keys/KESPERIOD
echo "export MAXKESEVOLUTIONS=${MAXKESEVOLUTIONS}" >> pool-keys/KESPERIOD
echo "export MAXKESSLOTS=${MAXKESSLOTS}" >> pool-keys/KESPERIOD
echo "export KESPERIOD=${KESPERIOD}" >> pool-keys/KESPERIOD
echo "export EXPIRESLOT=${EXPIRESLOT}" >> pool-keys/KESPERIOD
echo "Current slot: ${TIP}"
echo "slotsPerKesPeriod: ${SLOTSPERKESPERIOD}"
echo "KESPeriod: ${KESPERIOD}"
echo "MaxKESSlots: ${MAXKESSLOTS}"
echo "KESExpireSlot: ${EXPIRESLOT}"
# Create an operational node certificate
cardano-cli node issue-op-cert \
--kes-verification-key-file pool-keys/kes.vkey \
--cold-signing-key-file cold-keys/cold.skey \
--operational-certificate-issue-counter cold-keys/cold.counter \
--kes-period ${KESPERIOD} \
--out-file pool-keys/node.cert
echo "Successfully created node operational keys."

View File

@ -0,0 +1,167 @@
#!/bin/bash
# From Documentation
# https://github.com/input-output-hk/cardano-tutorials/blob/ecbfd0ec06e0515701ee3749ce96780c27d2249d/node-setup/080_register_stakepool.md
# Init vars
source /scripts/init_node_vars
source /scripts/functions/get_public_ip
source /scripts/functions/stakepool_info
TIMESTAMP=$(date +%s)
# Enter staking directory
cd ${NODE_PATH}/staking/
echo ""
echo "Generate registration certificates"
# Check for required files
if [ ! -f "wallets/owner/stake.vkey" ]; then
echo "Missing required staking/stake.vkey. You need to run \`generate_waller owner\` to generate this key."
MISSING_FILES=1
fi
if [ ! -f "cold-keys/cold.vkey" ]; then
echo "Missing required staking/cold-keys/cold.vkey. You need to run \`generate_operational_certificate\` to generate this key."
MISSING_FILES=1
fi
if [ ! -f "pool-keys/vrf.vkey" ]; then
echo "Missing required staking/pool-keys/vrf.vkey. You need to run \`generate_operational_certificate\` to generate this key."
MISSING_FILES=1
fi
if [ -n "$MISSING_FILES" ]; then
exit
fi
if [ -z "$METADATA_URL" ]; then
echo "Missing METADATA_URL You need to upload your metadata.json file at pass the URL to the METADATA_URL variable."
exit
fi
# Handle arguments
for i in "$@"
do
case $i in
--update)
UPDATE_CERT=1
;;
--cold-create)
COLD_CREATE=1
;;
esac
done
# 1. Create a JSON file with your pool's metadata
if [ ! -f "metadata.json" ] || [ -n "$UPDATE_CERT" ]; then
if [ -z "$COLD_CREATE" ]; then
echo "Getting metadata file from ${METADATA_URL}"
wget -O metadata.json ${METADATA_URL}
else
read -n 1 -r -s -p "Missing ${NODE_PATH}/staking/metadata.json. Please add this file, and ENTER when you have placed the file and are ready to continue."
fi
fi
# 2. get hash of file
echo "Getting hash of metadata.json"
METADATA_HASH=$(cardano-cli stake-pool metadata-hash --pool-metadata-file metadata.json)
echo "metadata.json hash: ${METADATA_HASH}"
# 3. Generate Stake pool registration certificate
if [ ! -f "pool.cert" ] || [ -n "$UPDATE_CERT" ]; then
if [ -f "pool.cert" ]; then
echo "backing up pool.cert."
cp pool.cert pool.${TIMESTAMP}.cert
fi
if [ "${PUBLIC_RELAY_IP}" == "TOPOLOGY" ]; then
PUBLIC_RELAY_IP=$(jq -r ".Producers[0].addr" ${NODE_PATH}/topology.json)
PUBLIC_RELAY_PORT=$(jq -r ".Producers[0].port" ${NODE_PATH}/topology.json)
fi
if [ "${PUBLIC_RELAY_IP}" == "PUBLIC" ]; then
PUBLIC_RELAY_IP=$(get_public_ip)
fi
if [ -z "$PUBLIC_RELAY_PORT" ]; then
PUBLIC_RELAY_PORT=$(jq -r ".Producers[0].port" ${NODE_PATH}/topology.json)
fi
echo "Generating pool.cert"
stakepool_info
echo "Public Relay IP: ${PUBLIC_RELAY_IP}"
echo "Public Relay Port: ${PUBLIC_RELAY_PORT}"
# Multiple owners
if [ -n "$MULTI_OWNERS" ]; then
echo "Multiple owners"
for i in $(echo ${MULTI_OWNERS} | sed "s/,/ /g")
do
echo "$i"
MULTIOWNERS_STRING="${MULTIOWNERS_STRING} --pool-owner-stake-verification-key-file wallets/${i}/stake.vkey"
done
echo $MULTIOWNERS_STRING
echo ""
fi
cardano-cli stake-pool registration-certificate \
--cold-verification-key-file cold-keys/cold.vkey \
--vrf-verification-key-file pool-keys/vrf.vkey \
--pool-pledge ${POOL_PLEDGE} \
--pool-cost ${POOL_COST} \
--pool-margin ${POOL_MARGIN} \
--pool-reward-account-verification-key-file wallets/owner/stake.vkey \
--pool-owner-stake-verification-key-file wallets/owner/stake.vkey \
${MULTIOWNERS_STRING} \
--pool-relay-port ${PUBLIC_RELAY_PORT} \
--pool-relay-ipv4 ${PUBLIC_RELAY_IP} \
--metadata-url ${METADATA_URL} \
--metadata-hash ${METADATA_HASH} \
${NETWORK_ARGUMENT} \
--out-file pool.cert \
&& echo "Generated pool.cert"
PAYMENT_ADDR=$(cat ${NODE_PATH}/staking/wallets/owner/payment.addr)
STAKE_ADDR=$(cat ${NODE_PATH}/staking/wallets/owner/stake.addr)
POOL_ID=$(cat ${NODE_PATH}/staking/POOL_ID)
echo "export POOL_PLEDGE=${POOL_PLEDGE}" > POOL_VARS
echo "export POOL_COST=${POOL_COST}" >> POOL_VARS
echo "export POOL_MARGIN=${POOL_MARGIN}" >> POOL_VARS
echo "export POOL_MARGIN=${POOL_MARGIN}" >> POOL_VARS
echo "export PAYMENT_ADDR=${PAYMENT_ADDR}" >> POOL_VARS
echo "export STAKE_ADDR=${STAKE_ADDR}" >> POOL_VARS
echo "export POOL_ID=${POOL_ID}" >> POOL_VARS
echo "export MULTI_OWNERS=${MULTI_OWNERS}" >> POOL_VARS
echo ""
else
echo "pool.cert already exists."
fi
# 2. Generate delegation certificate (pledge)
if [ ! -f "wallets/owner/delegation.cert" ]; then
cardano-cli stake-address delegation-certificate \
--stake-verification-key-file wallets/owner/stake.vkey \
--cold-verification-key-file cold-keys/cold.vkey \
--out-file wallets/owner/delegation.cert \
&& echo "Generated delegation.cert"
else
echo "delegation.cert already exists."
fi
# Multiple owners
if [ -n "$MULTI_OWNERS" ]; then
echo "Generating delegation certificates for multiple owners"
for i in $(echo ${MULTI_OWNERS} | sed "s/,/ /g")
do
echo "- $i"
if [ ! -f "wallets/$i/delegation.cert" ]; then
cardano-cli stake-address delegation-certificate \
--stake-verification-key-file wallets/$i/stake.vkey \
--cold-verification-key-file cold-keys/cold.vkey \
--out-file wallets/$i/delegation.cert \
&& echo "Generated delegation.cert"
else
echo "-- delegation.cert already exists."
fi
done
fi

66
scripts/generate_wallet Normal file
View File

@ -0,0 +1,66 @@
#!/bin/bash
# Following guide:
# https://github.com/input-output-hk/cardano-tutorials/blob/master/node-setup/020_keys_and_addresses.md
# Init node vars
source /scripts/init_node_vars
WALLET=$1
mkdir -p ${NODE_PATH}/staking/wallets/${WALLET}
cd ${NODE_PATH}/staking/wallets/${WALLET}
echo ""
echo "Generate stake addresses"
# Generate key & address
## Generate Payment key pair
if [ ! -f "payment.skey" ]; then
cardano-cli address key-gen \
--verification-key-file payment.vkey \
--signing-key-file payment.skey
echo "Generated payment.vkey and payment.skey."
else
echo "Payment key pair already exists."
fi
## Generate Stake key pair
if [ ! -f "stake.skey" ]; then
cardano-cli stake-address key-gen \
--verification-key-file stake.vkey \
--signing-key-file stake.skey
echo "Generated stake.vkey and stake.skey."
else
echo "Stake key pair already exists."
fi
## Generate Payment address
if [ ! -f "payment.addr" ]; then
cardano-cli address build \
--payment-verification-key-file payment.vkey \
--stake-verification-key-file stake.vkey \
--out-file payment.addr \
--mainnet
echo "Generated payment.addr."
PAYMENT_ADDR=$(cat payment.addr)
echo "Payment address: ${PAYMENT_ADDR}."
else
PAYMENT_ADDR=$(cat payment.addr)
echo "Payment address already exists: ${PAYMENT_ADDR}."
fi
## Generate Stake address
if [ ! -f "stake.addr" ]; then
cardano-cli stake-address build \
--stake-verification-key-file stake.vkey \
--out-file stake.addr \
--mainnet
echo "Generated stake.addr."
STAKE_ADDR=$(cat stake.addr)
echo "Stake address: ${STAKE_ADDR}."
else
STAKE_ADDR=$(cat stake.addr)
echo "Stake address already exists: ${STAKE_ADDR}."
fi

View File

@ -0,0 +1,10 @@
import os
from init_config import parse_topology_str
if __name__ == '__main__':
topology = parse_topology_str(os.environ.get('NODE_TOPOLOGY', ''))
_topology = []
for t in topology:
_topology.append('%s:%s:%s' % (t.get('addr'), t.get('port'), t.get('valency')))
print('|'.join(_topology))

166
scripts/init_config.py Normal file
View File

@ -0,0 +1,166 @@
import os
import shutil
import re
import argparse
import json
import socket
import time
CONFIG_TEMPLATES_ROOT_PATH = '/cfg-templates/'
CONFIG_OUTPUT_ROOT_PATH = '/config/'
def slugify(value):
"""
Normalizes string, converts to lowercase, removes non-alpha characters,
and converts spaces to hyphens.
"""
value = re.sub('[^-a-zA-Z0-9_.]+', '', value)
return value
def str2bool(v:str):
"""Converts string to boolean"""
return v.lower() in ('yes', 'true', 't', '1')
def save_json(path:str, data):
with open(path, 'w') as outfile:
json.dump(data, outfile, indent=1)
def load_json(path:str):
with open(path, 'r') as inputfile:
return json.load(inputfile)
def init_args():
# Parse arguments
parser = argparse.ArgumentParser(description='Cardano Configurator')
parser.add_argument('--node-port', dest='node_port', help='Port of node. Defaults to 3000.', type=int, default=os.environ.get('NODE_PORT', 3000))
parser.add_argument('--node-name', dest='name', help='Name of node. Defaults to node1.', type=slugify, default=os.environ.get('NODE_NAME', 'node1'))
parser.add_argument('--node-topology', dest='topology', help='Topology of the node. Should be comma separated for each individual node to add, on the form: <ip>:<port>/<valency>. So for example: 127.0.0.1:3001/1,127.0.0.1:3002/1.', type=str, default=os.environ.get('NODE_TOPOLOGY', ''))
parser.add_argument('--node-relay', dest='relay', help='Set to 1 if default IOHK relay should be added to the network topology.', type=str2bool, default=os.environ.get('NODE_RELAY', False))
parser.add_argument('--cardano-network', dest='network', help='Carano network to use (main, test, pioneer). Defaults to main.', type=str, default=os.environ.get('CARDANO_NETWORK', 'main'))
parser.add_argument('--ekg-port', dest='ekg_port', help='Port of EKG monitoring. Defaults to 12788.', type=int, default=os.environ.get('EKG_PORT', 12788))
parser.add_argument('--prometheus-host', dest='prometheus_host', help='Host of Prometheus monitoring. Defaults to 127.0.0.1.', type=str, default=os.environ.get('PROMETHEUS_HOST', '127.0.0.1'))
parser.add_argument('--prometheus-port', dest='prometheus_port', help='Port of Prometheus monitoring. Defaults to 12798.', type=int, default=os.environ.get('PROMETHEUS_PORT', 12798))
parser.add_argument('--resolve-hostnames', dest='resolve_hostnames', help='Resolve hostnames in topology to IP-addresses.', type=str2bool, default=os.environ.get('RESOLVE_HOSTNAMES', False))
parser.add_argument('--replace-existing', dest='replace_existing', help='Replace existing configs.', type=str2bool, default=os.environ.get('REPLACE_EXISTING_CONFIG', False))
args = parser.parse_args()
# Init network specific paths
args.CONFIG_TEMPLATES_PATH = os.path.join(CONFIG_TEMPLATES_ROOT_PATH, args.network)
CONFIG_NAME = args.network+'-'+args.name
args.CONFIG_OUTPUT_PATH = os.path.join(CONFIG_OUTPUT_ROOT_PATH, CONFIG_NAME)
args.BYRON_GENESIS_PATH = os.path.join(args.CONFIG_OUTPUT_PATH, 'byron-genesis.json')
args.SHELLEY_GENESIS_PATH = os.path.join(args.CONFIG_OUTPUT_PATH, 'shelley-genesis.json')
args.TOPOLOGY_PATH = os.path.join(args.CONFIG_OUTPUT_PATH, 'topology.json')
args.CONFIG_PATH = os.path.join(args.CONFIG_OUTPUT_PATH, 'config.json')
args.VARS_PATH = os.path.join(args.CONFIG_OUTPUT_PATH, 'VARS')
return args
def init_folder(args):
"""Creates network/node config folders"""
if not os.path.exists(args.CONFIG_OUTPUT_PATH):
os.makedirs(args.CONFIG_OUTPUT_PATH)
def init_genesis(args):
"""Initializes the genesis file"""
SHELLEY_SRC = os.path.join(args.CONFIG_TEMPLATES_PATH, 'shelley-genesis.json')
BYRON_SRC = os.path.join(args.CONFIG_TEMPLATES_PATH, 'byron-genesis.json')
if not os.path.exists(args.SHELLEY_GENESIS_PATH) or args.replace_existing:
print('Generating new shelley genesis file %s from template %s' % (args.SHELLEY_GENESIS_PATH, SHELLEY_SRC))
shutil.copy(SHELLEY_SRC, args.SHELLEY_GENESIS_PATH)
if not os.path.exists(args.BYRON_GENESIS_PATH) or args.replace_existing:
print('Generating new byron genesis file %s from template %s' % (args.BYRON_GENESIS_PATH, BYRON_SRC))
shutil.copy(BYRON_SRC, args.BYRON_GENESIS_PATH)
def resolve_hostname(hostname, tries=0):
"""Resolve IP from hostname"""
try:
return socket.gethostbyname(hostname)
except:
if tries<10:
time.sleep(1)
return resolve_hostname(hostname, tries=tries+1)
else:
return hostname
def parse_topology_str(s) -> list:
"""Parses node-topology string and returns list of dicts"""
topology = []
if s:
for a in s.split(','):
(ip_port, valency) = a.split('/')
(ip, port) = ip_port.split(':')
#if resolve_hostname: ip = resolve_hostname(ip)
topology.append({
'addr': str(ip),
'port': int(port),
'valency': int(valency)
})
return topology
def init_topology(args):
"""Initializes the topology file"""
if args.relay:
INPUT_PATH = os.path.join(args.CONFIG_TEMPLATES_PATH, 'topology-relay.json')
else:
INPUT_PATH = os.path.join(args.CONFIG_TEMPLATES_PATH, 'topology.json')
if not os.path.exists(args.TOPOLOGY_PATH) or args.replace_existing:
print('Generating new topology %s from template %s' % (args.TOPOLOGY_PATH, INPUT_PATH))
print('Topology: ', args.topology)
# Load template file
data = load_json(INPUT_PATH)
# Parse topology string
topology = parse_topology_str(args.topology)
# Add default IOHK relay
data['Producers'] = data['Producers']+topology
save_json(args.TOPOLOGY_PATH, data)
def init_config(args):
"""Initializes the config file"""
INPUT_PATH = os.path.join(args.CONFIG_TEMPLATES_PATH, 'config.json')
if not os.path.exists(args.CONFIG_PATH) or args.replace_existing:
print('Generating new config file %s from template %s' % (args.CONFIG_PATH, INPUT_PATH))
data = load_json(INPUT_PATH)
data['hasEKG'] = args.ekg_port
data['hasPrometheus'] = [args.prometheus_host, args.prometheus_port]
data['ShelleyGenesisFile'] = args.SHELLEY_GENESIS_PATH
data['ByronGenesisFile'] = args.BYRON_GENESIS_PATH
save_json(args.CONFIG_PATH, data)
def init_vars(args):
INPUT_PATH = os.path.join(args.CONFIG_TEMPLATES_PATH, 'VARS')
if not os.path.exists(args.VARS_PATH) or args.replace_existing:
print('Generating new VARS %s from template %s' % (args.VARS_PATH, INPUT_PATH))
# Just copy it
shutil.copy(INPUT_PATH, args.VARS_PATH)
if __name__ == '__main__':
args = init_args()
init_folder(args)
init_genesis(args)
init_topology(args)
init_config(args)
init_vars(args)

7
scripts/init_node_vars Normal file
View File

@ -0,0 +1,7 @@
#!/bin/bash
export NODE_PATH=/config/${CARDANO_NETWORK}-${NODE_NAME}/
if [[ "${CARDANO_NODE_SOCKET_PATH}" == "DEFAULT" ]]; then
export CARDANO_NODE_SOCKET_PATH=${NODE_PATH}node.socket
fi
source ${NODE_PATH}VARS

26
scripts/leaderlogs.sh Normal file
View File

@ -0,0 +1,26 @@
#!/bin/bash
source /scripts/init_node_vars
# Init vars
POOL_ID=$(cat ${NODE_PATH}staking/POOL_ID)
TZ=$(cat /etc/timezone)
VRF=${NODE_PATH}staking/pool-keys/vrf.skey
echo "Dumping ledger.json"
cardano-cli query ledger-state --allegra-era ${NETWORK_ARGUMENT} --out-file ${NODE_PATH}ledger.json
echo "Calculating sigma"
SIGMA=$(python3 /scripts/pooltool.io/leaderLogs/getSigma.py --pool-id ${POOL_ID} --ledger ${NODE_PATH}ledger.json | tail -1 | awk '{print $2}')
# Print vars
echo "POOL_ID: ${SIGMA}"
echo "TZ: ${TZ}"
echo "VRF: ${VRF}"
echo "SIGMA: ${SIGMA}"
# Get leaderlogs
python3 /scripts/pooltool.io/leaderLogs/leaderLogs.py \
--vrf-skey ${VRF} \
--sigma ${SIGMA} \
--tz ${TZ}

View File

@ -0,0 +1,195 @@
#!/bin/bash
# From Documentation
# https://github.com/input-output-hk/cardano-tutorials/blob/master/node-setup/040_transactions.md
# https://github.com/input-output-hk/cardano-tutorials/blob/master/node-setup/050_register_key.md
# Init functions and vars
source /scripts/functions/check_balance
source /scripts/functions/check_address_registration
source /scripts/functions/wait_for_address_registration
source /scripts/functions/wait_for_slot
source /scripts/functions/wait_for_sync
source /scripts/init_node_vars
# Define wallet
WALLET=$1
if [ -z "$WALLET" ]; then
echo "Wallet is undefined."
exit
fi
# Enter staking directory
cd ${NODE_PATH}/staking/wallets/${WALLET}
STAKE_ADDR=$(cat ${NODE_PATH}/staking/wallets/${WALLET}/stake.addr)
echo ""
echo "Submitting staking addresses for $WALLET to the blockchain."
# Check for required files
if [ ! -f "stake.vkey" ]; then
echo "Missing required wallets/${WALLET}/stake.vkey. You need to run \`generate_wallet ${WALLET}\` to generate this key."
MISSING_FILES=1
fi
if [ ! -f "stake.skey" ]; then
echo "Missing required wallets/${WALLET}/stake.skey. You need to run \`generate_wallet ${WALLET}\` to generate this key."
MISSING_FILES=1
fi
if [ ! -f "payment.skey" ]; then
echo "Missing required wallets/${WALLET}/payment.skey. You need to run \`generate_wallet ${WALLET}\` to generate this key."
MISSING_FILES=1
fi
if [ ! -f "payment.addr" ]; then
echo "Missing required wallets/${WALLET}/payment.addr. You need to run \`generate_wallet ${WALLET}\` to generate this key."
MISSING_FILES=1
fi
if [ -n "$MISSING_FILES" ]; then
exit
fi
# Handle arguments
for i in "$@"; do
case $i in
--cold-create)
COLD_CREATE=1
;;
esac
done
mkdir -p transactions
# Wait for node to sync
if [[ "${WAIT_FOR_SYNC}" == "True" ]]; then
wait_for_sync 99.90
fi
if [ -z "$COLD_CREATE" ]; then
if [ -n "$(check_address_registration ${STAKE_ADDR})" ]; then
echo "Your stake address has already been registered in the blockchain."
touch transactions/register_stake_address.submitted
exit
fi
fi
# Create an address registration certificate
if [ ! -f "stake.cert" ]; then
cardano-cli stake-address registration-certificate \
--staking-verification-key-file stake.vkey \
--out-file stake.cert
echo "Created stake.cert"
else
echo "stake.cert certificate already exists."
fi
# Generate protocol
if [ -z "$COLD_CREATE" ]; then
cardano-cli query protocol-parameters \
${NETWORK_ARGUMENT} --allegra-era \
--out-file ${NODE_PATH}/staking/protocol.json
else
if [ ! -f "${NODE_PATH}/staking/protocol.json" ]; then
read -n 1 -r -s -p "Missing ${NODE_PATH}/staking/protocol.json. You must transfer this file from an online node. Press ENTER when you have placed the file and are ready to continue."
fi
fi
# Get key-deposit
KEY_DEPOSIT=$(jq -r .keyDeposit ${NODE_PATH}/staking/protocol.json)
POOL_DEPOSIT=$(jq -r .poolDeposit ${NODE_PATH}/staking/protocol.json)
MIN_HOLDING=$(expr $KEY_DEPOSIT + $POOL_DEPOSIT + $POOL_PLEDGE)
# Find UTXO in address with enough lovelace to do the transaction
ADDRESS=$(cat payment.addr)
check_balance ${KEY_DEPOSIT}
# Draft transaction
cardano-cli transaction build-raw \
--tx-in "${UTXO}#${TXIX}" \
--tx-out ${ADDRESS}+0 \
--ttl 0 \
--fee 0 \
--out-file transactions/register_stake_address.draft \
--certificate-file stake.cert
# Calculate fees
FEE=$(cardano-cli transaction calculate-min-fee \
--tx-body-file transactions/register_stake_address.draft \
--tx-in-count 1 \
--tx-out-count 1 \
--witness-count 1 \
--byron-witness-count 0 \
${NETWORK_ARGUMENT} \
--protocol-params-file ${NODE_PATH}/staking/protocol.json | tr ' ' '\n' | head -1)
TOTAL_PRICE=$(expr ${FEE} + ${KEY_DEPOSIT})
echo "Fee is: ${FEE} Lovelace"
echo "Key-Deposit: ${KEY_DEPOSIT} Lovelace"
echo "Total Price is: ${TOTAL_PRICE}"
# Find UTXO in address with enough lovelace to do the transaction
if [ -z "$COLD_CREATE" ]; then
check_balance ${TOTAL_PRICE}
SLOT=$(get_slot)
else
read -p "Enter the current tip slot: " SLOT
fi
# Get slot and TTL
TTL=$(expr ${SLOT} + 500)
# Display transaction info
REMAINING_AFTER_TX=$(expr ${LOVELACE} - ${TOTAL_PRICE})
echo "Creating transaction"
echo "Lovelace after transaction: ${REMAINING_AFTER_TX}"
echo "Current slot: ${SLOT}"
echo "TTL: ${TTL}"
#
# Create the transaction
#
cardano-cli transaction build-raw \
--tx-in "${UTXO}#${TXIX}" \
--tx-out ${ADDRESS}+${REMAINING_AFTER_TX} \
--ttl ${TTL} \
--fee ${FEE} \
--out-file transactions/register_stake_address.raw \
--certificate-file stake.cert
# Sign the transaction
cardano-cli transaction sign \
--tx-body-file transactions/register_stake_address.raw \
--signing-key-file payment.skey \
--signing-key-file stake.skey \
${NETWORK_ARGUMENT} \
--out-file transactions/register_stake_address.signed
# Submit the transaction
if [ -z "$COLD_CREATE" ]; then
read -n 1 -r -s -p $'Press enter to submit the stake address certificate...\n'
OUT=$(cardano-cli transaction submit \
--tx-file transactions/register_stake_address.signed \
${NETWORK_ARGUMENT} 2>&1)
if [[ $OUT =~ "Error" ]]
then
echo "An error occoured."
echo ${OUT}
read
else
echo "Transaction has been submitted to the blockchain."
echo ${OUT}
# Wait for blockchain to register the address
wait_for_slot ${TTL}
wait_for_address_registration ${STAKE_ADDR}
echo "Your stake address is now registered in the blockchain."
touch transactions/register_stake_address.submitted
fi
fi

225
scripts/register_stake_pool Normal file
View File

@ -0,0 +1,225 @@
#!/bin/bash
# From Documentation
# https://github.com/input-output-hk/cardano-tutorials/blob/master/node-setup/080_register_stakepool.md
# Init vars
source /scripts/functions/check_balance
source /scripts/functions/check_pool_registration
source /scripts/functions/wait_for_pool_registration
source /scripts/functions/wait_for_slot
source /scripts/functions/wait_for_sync
source /scripts/init_node_vars
TIMESTAMP=$(date +%s)
# Enter staking directory
cd ${NODE_PATH}/staking/
mkdir -p wallets/owner/transactions
echo ""
echo "Submitting stake pool certificates to the blockchain."
# Check for required files
if [ ! -f "wallets/owner/stake.skey" ]; then
echo "Missing required wallets/${WALLET}/stake.skey. You need to run \`generate_waller owner\` to generate this key."
MISSING_FILES=1
fi
if [ ! -f "wallets/owner/payment.skey" ]; then
echo "Missing required wallets/${WALLET}/payment.skey. You need to run \`generate_waller owner\` to generate this key."
MISSING_FILES=1
fi
if [ ! -f "wallets/owner/payment.addr" ]; then
echo "Missing required wallets/${WALLET}/payment.addr. You need to run \`generate_waller owner\` to generate this key."
MISSING_FILES=1
fi
if [ ! -f "cold-keys/cold.skey" ]; then
echo "Missing required staking/cold-keys/cold.skey. You need to run \`generate_operational_certificate\` to generate this key."
MISSING_FILES=1
fi
if [ ! -f "pool.cert" ]; then
echo "Missing required staking/pool.cert. You need to run \`generate_registration_certificate\` to generate this certificate."
MISSING_FILES=1
fi
if [ ! -f "wallets/owner/delegation.cert" ]; then
echo "Missing required staking/wallets/owner/delegation.cert. You need to run \`generate_registration_certificate\` to generate this certificate."
MISSING_FILES=1
fi
if [ -n "$MISSING_FILES" ]; then
exit
fi
# Handle arguments
for i in "$@"
do
case $i in
--update)
UPDATE=1
;;
--no_deleg)
NO_DELEG=1
;;
--cold-create)
COLD_CREATE=1
;;
esac
done
EXTRA_FEE=9000
if [ -z "$COLD_CREATE" ]; then
if [ -z "$UPDATE" ]; then
if [ -n "$(check_pool_registration)" ]; then
echo "Your stake pool has already been registered in the blockchain."
touch ${NODE_PATH}/staking/wallets/owner/transactions/register_stake_pool.submitted
exit
fi
else
if [ -z "$(check_pool_registration)" ]; then
echo "Pool is not registered in the blockchain. You cannot update the certificates. Register the stakepool first."
exit
fi
fi
fi
# Wait for node to sync
if [[ "${WAIT_FOR_SYNC}" == "True" ]]; then
wait_for_sync 99.90
fi
# Generate protocol
if [ -z "$COLD_CREATE" ]; then
cardano-cli query protocol-parameters \
${NETWORK_ARGUMENT} --allegra-era \
--out-file ${NODE_PATH}/staking/protocol.json
else
if [ ! -f "${NODE_PATH}/staking/protocol.json" ]; then
read -n 1 -r -s -p "Missing ${NODE_PATH}/staking/protocol.json. You must transfer this file from an online node. Press ENTER when you have placed the file and is ready to continue."
fi
fi
# Get pool-deposit
if [ -z "$UPDATE" ]; then
POOL_DEPOSIT=$(jq -r .poolDeposit protocol.json)
else
POOL_DEPOSIT=0
fi
# Find UTXO in address with enough lovelace to do the transaction
ADDRESS=$(cat wallets/owner/payment.addr)
check_balance $(expr ${POOL_DEPOSIT} + ${EXTRA_FEE})
# Multiowners delegation certificates
if [ -n "$MULTI_OWNERS" ]; then
echo "Multiple owner delegation certificates"
for i in $(echo ${MULTI_OWNERS} | sed "s/,/ /g")
do
echo "$i"
MULTIOWNERS_CERT_STRING="${MULTIOWNERS_STRING} --certificate-file wallets/$i/delegation.cert"
MULTIOWNERS_SIGN="${MULTIOWNERS_SIGN} --signing-key-file wallets/$i/stake.skey"
done
echo $MULTIOWNERS_STRING
fi
if [ -z "$NO_DELEG" ]; then
DELEG_CERTS="--certificate-file wallets/owner/delegation.cert ${MULTIOWNERS_CERT_STRING}"
fi
# Draft transaction
cardano-cli transaction build-raw \
--tx-in "${UTXO}#${TXIX}" \
--tx-out ${ADDRESS}+0 \
--ttl 0 \
--fee 0 \
--out-file wallets/owner/transactions/register_stake_pool.draft \
--certificate-file pool.cert ${DELEG_CERTS}
## Calculate the fee
FEE=$(cardano-cli transaction calculate-min-fee \
--tx-body-file wallets/owner/transactions/register_stake_pool.draft \
--tx-in-count 1 \
--tx-out-count 1 \
${NETWORK_ARGUMENT} \
--witness-count 1 \
--byron-witness-count 0 \
--protocol-params-file protocol.json | tr ' ' '\n' | head -1)
FEE=$(expr ${FEE} + ${EXTRA_FEE}) # FEE IS TOO SMALL?
TOTAL_PRICE=$(expr ${FEE} + ${POOL_DEPOSIT})
echo "Fee is: ${FEE} Lovelace"
echo "Pool-Deposit: ${POOL_DEPOSIT} Lovelace"
echo "Total Price is: ${TOTAL_PRICE} Lovelace"
# Find UTXO in address with enough lovelace to do the transaction
if [ -z "$COLD_CREATE" ]; then
check_balance ${TOTAL_PRICE}
SLOT=$(get_slot)
else
read -p "Enter the current tip slot: " SLOT
fi
TTL=$(expr ${SLOT} + 500)
# Display transaction info
REMAINING_AFTER_TX=$(expr ${LOVELACE} - ${TOTAL_PRICE})
echo "Creating transaction"
echo "Lovelace after transaction: ${REMAINING_AFTER_TX}"
echo "Current tip Slot: ${SLOT}"
echo "TTL: ${TTL}"
#
# Create the transaction
#
echo "Create transaction"
cardano-cli transaction build-raw \
--tx-in "${UTXO}#${TXIX}" \
--tx-out ${ADDRESS}+${REMAINING_AFTER_TX} \
--ttl ${TTL} \
--fee ${FEE} \
--out-file wallets/owner/transactions/register_stake_pool.raw \
--certificate-file pool.cert \
--certificate-file wallets/owner/delegation.cert \
${MULTIOWNERS_CERT_STRING}
# Sign the transaction
echo "Sign transaction"
cardano-cli transaction sign \
--tx-body-file wallets/owner/transactions/register_stake_pool.raw \
--signing-key-file wallets/owner/payment.skey \
--signing-key-file wallets/owner/stake.skey \
${MULTIOWNERS_SIGN} \
--signing-key-file cold-keys/cold.skey \
${NETWORK_ARGUMENT} \
--out-file wallets/owner/transactions/register_stake_pool.signed
# Submit the transaction
if [ -z "$COLD_CREATE" ]; then
read -n 1 -r -s -p $'Press enter to submit the certificates...\n'
echo "Submit transaction"
OUT=$(cardano-cli transaction submit \
--tx-file wallets/owner/transactions/register_stake_pool.signed \
${NETWORK_ARGUMENT} 2>&1)
if [[ $OUT =~ "Error" ]]
then
echo "An error occoured."
echo ${OUT}
read
else
echo "Transaction has been submitted to the blockchain."
echo ${OUT}
# Wait for blockchain to register the pool
wait_for_slot ${TTL}
wait_for_pool_registration
echo "Your stake pool registration has been sent to the blockchain."
touch ${NODE_PATH}/staking/wallets/owner/transactions/register_stake_pool.submitted
fi
fi

136
scripts/send_ada Normal file
View File

@ -0,0 +1,136 @@
#!/bin/bash
source /scripts/functions/check_balance
WALLET=$1
TO_ADDR=$2
SEND_ADA=$3
TIMESTAMP=$(date +%s)
if [ -z "$WALLET" ]; then
echo "Invalid wallet."
MISSING_ARG=1
fi
if [ -z "$TO_ADDR" ]; then
echo "Invalid recipient address."
MISSING_ARG=1
fi
if [ -z "$SEND_ADA" ]; then
echo "Missing ADA amount."
MISSING_ARG=1
fi
if [ -n "$MISSING_ARG" ]; then
exit
fi
# Check for required files
if [ ! -f "${NODE_PATH}/staking/wallets/${WALLET}/payment.skey" ]; then
echo "Missing required payment.skey. You need to run \`generate_waller ${WALLET}\` to generate this key."
MISSING_FILES=1
fi
if [ ! -f "${NODE_PATH}/staking/wallets/${WALLET}/payment.addr" ]; then
echo "Missing required payment.addr. You need to run \`generate_waller ${WALLET}\` to generate this key."
MISSING_FILES=1
fi
if [ -n "$MISSING_FILES" ]; then
exit
fi
cd ${NODE_PATH}/staking/wallets/${WALLET}/
mkdir -p transactions/
# Wait for node to sync
if [[ "${WAIT_FOR_SYNC}" == "True" ]]; then
wait_for_sync 99.90
fi
cardano-cli query protocol-parameters \
${NETWORK_ARGUMENT} --allegra-era \
--out-file ${NODE_PATH}/staking/protocol.json
ADDRESS=$(cat payment.addr)
SEND_LOVELACE=$(expr ${SEND_ADA} \* 1000000) # Convert ADA to Lovelace
check_balance $SEND_LOVELACE
# Draft transaction
cardano-cli transaction build-raw \
--tx-in "${UTXO}#${TXIX}" \
--tx-out ${TO_ADDR}+0 \
--tx-out ${ADDRESS}+0 \
--ttl 0 \
--fee 0 \
--out-file transactions/tx.${TIMESTAMP}.draft
FEE=$(cardano-cli transaction calculate-min-fee \
--tx-body-file transactions/tx.${TIMESTAMP}.draft \
--tx-in-count 1 \
--tx-out-count 2 \
${NETWORK_ARGUMENT} \
--witness-count 1 \
--byron-witness-count 0 \
--protocol-params-file ${NODE_PATH}/staking/protocol.json | tr ' ' '\n' | head -1)
TOTAL_PRICE=$(expr ${FEE} + ${SEND_LOVELACE})
# Find UTXO in address with enough lovelace to do the transaction
check_balance ${TOTAL_PRICE}
# Update slot and TTL
SLOT=$(get_slot)
TTL=$(expr ${SLOT} + 500)
# Display transaction info
REMAINING_AFTER_TX=$(expr ${LOVELACE} - ${TOTAL_PRICE})
echo "Creating transaction"
echo "Current tip Slot: ${SLOT}"
echo "TTL: ${TTL}"
echo ""
echo "$SEND_ADA ADA is ${SEND_LOVELACE} Lovelace"
echo "From wallet: ${WALLET}"
echo "From address: ${ADDRESS}"
echo "To address: ${TO_ADDR}"
echo "Send amount: ${SEND_LOVELACE} Lovelace"
echo "Fee is: ${FEE} Lovelace"
echo "Total amount is: ${TOTAL_PRICE} Lovelace"
echo "Balance after transaction: ${REMAINING_AFTER_TX} Lovelace"
#
# Create the transaction
#
echo "Create transaction"
cardano-cli transaction build-raw \
--tx-in "${UTXO}#${TXIX}" \
--tx-out ${TO_ADDR}+${SEND_LOVELACE} \
--tx-out ${ADDRESS}+${REMAINING_AFTER_TX} \
--ttl ${TTL} \
--fee ${FEE} \
--out-file transactions/tx.${TIMESTAMP}.raw
cardano-cli transaction sign \
--tx-body-file transactions/tx.${TIMESTAMP}.raw \
--signing-key-file payment.skey \
${NETWORK_ARGUMENT} \
--out-file transactions/tx.${TIMESTAMP}.signed
# Submit the transaction
read -n 1 -r -s -p $'Press enter to submit the transaction...\n'
echo "Submit transaction"
OUT=$(cardano-cli transaction submit \
--tx-file transactions/tx.${TIMESTAMP}.signed \
${NETWORK_ARGUMENT} 2>&1)
if [[ $OUT =~ "Error" ]]
then
echo "An error occoured."
echo ${OUT}
read
else
echo "Transaction has been submitted to the blockchain."
echo ${OUT}
fi

128
scripts/start-cardano-node Normal file
View File

@ -0,0 +1,128 @@
#!/bin/bash
# Include functions
source /scripts/init_node_vars
source /scripts/functions/run_node
source /scripts/functions/get_public_ip
source /scripts/functions/init_config
function help {
echo "Arguments:"
echo "--start Start basic node."
echo "--staking Start as a staking node (Also requires the \`--start\` argument)"
echo "--create Start Stakepool creation. Initializes Stake Pool keys, addresses and certificates, and sends them to the blockchain, when starting as a stakepool, if it is not already initialized."
echo "--cold-create Initializes Stake Pool keys, addresses and certificates, and sign registration transactions. Registation transactions has to be sent using the \`--cold-register\` argument."
echo "--cold-register Submits the address and pool registration transactions to the blockchain created using the \`--cold-create\` argument."
echo "--cli Start command-line interface."
echo "--update Update the node software."
echo "--init_config Initialize config."
echo "--help Display this message."
echo "Environment variables:"
echo "NODE_PORT Port of node. Default: 3000."
echo "NODE_NAME Name of node. Default: node1."
echo "NODE_TOPOLOGY Topology of the node. Should be comma separated for each individual node to add, on the form: <ip>:<port>/<valency>. So for example: 127.0.0.1:3001/1,127.0.0.1:3002/1."
echo "NODE_RELAY Set to True if default IOHK relay should be added to the network topology. Default: False."
echo "METADATA_URL URL for file containing stake pool metadata information. See \`examples/metadata.json\` for examle. The file be uploaded to an URL accessible to public."
echo "PUBLIC_RELAY_PORT Public port of Relay node."
echo "PUBLIC_RELAY_IP Public IP address of Relay node."
echo " Values:"
echo " <Any IP address>"
echo " TOPOLOGY: Use first entry of the topology."
echo " PUBLIC: Use public IP of node."
echo " Default: TOPOLOGY."
echo "HOST_ADDR Set cardano-node host address. Defaults to public IP address."
echo "CARDANO_NETWORK Carano network to use (main, test, pioneer). Default: main."
echo "EKG_PORT Port of EKG monitoring. Default: 12788."
echo "PROMETHEUS_HOST Host of Prometheus monitoring. Default: 127.0.0.1."
echo "PROMETHEUS_PORT Port of Prometheus monitoring. Default: 12798."
echo "RESOLVE_HOSTNAMES Resolve topology hostnames to IP-addresses. Default: False."
echo "REPLACE_EXISTING_CONFIG Reset and replace existing configs. Default: False."
echo "POOL_PLEDGE Pledge (lovelace). Default: 100000000000"
echo "POOL_COST Operational costs per epoch (lovelace). Default: 10000000000"
echo "POOL_MARGIN Operator margin. Default: 0.05"
echo "AUTO_TOPOLOGY Automatically update topology.json. Default: True"
exit
}
for i in "$@"; do
case $i in
--help)
help
break
;;
--update)
/scripts/update-cardano-node
;;
--cli)
/bin/bash
break
;;
--init_config)
init_config
;;
--start)
START_NODE=1
;;
--staking)
STAKING=1
;;
--create)
CREATE=1
;;
--cold-create)
CREATE=1
COLD_CREATE=1
COLD="${COLD} --cold-create"
;;
--cold-register)
CREATE=1
COLD="${COLD} --cold-register"
;;
*)
break
;;
esac
done
if [ -z "$1" ]; then
help
fi
# Init config on first run
if [[ ! -f "${NODE_PATH}/VARS" || "$REPLACE_EXISTING_CONFIG" == "True" ]]; then
init_config
fi
# If not doing cold-create
if [ -z "${COLD_CREATE}" ]; then
# Handle IP addresses
export PUBLIC_IP=$(get_public_ip)
if [ -z "${HOST_ADDR}" ]; then
export HOST_ADDR=${PUBLIC_IP}
fi
fi
if [ -n "$CREATE" ]; then
create_stakepool ${COLD}
fi
if [ -n "$START_NODE" ]; then
if [ -n "$STAKING" ]; then
# Start as staking node
/scripts/start-stakenode
else
# Update topology
if [[ "${AUTO_TOPOLOGY}" == "True" ]]; then
tmux \
new-session "source /scripts/functions/run_node; run_node" \; \
split-window "source /scripts/functions/auto_topology_start; auto_topology_start" \; \
select-layout even-horizontal
else
run_node
fi
fi
fi

39
scripts/start-stakenode Normal file
View File

@ -0,0 +1,39 @@
#!/bin/bash
source /scripts/init_node_vars
source /scripts/functions/check_pool_registration
# Check for required files
if [ ! -f "${NODE_PATH}/staking/pool-keys/kes.skey" ]; then
echo "Missing required pool-keys/kes.skey."
MISSING_FILES=1
fi
if [ ! -f "${NODE_PATH}/staking/pool-keys/vrf.skey" ]; then
echo "Missing required pool-keys/vrf.skey."
MISSING_FILES=1
fi
if [ ! -f "${NODE_PATH}/staking/pool-keys/node.cert" ]; then
echo "Missing required pool-keys/node.cert."
MISSING_FILES=1
fi
if [ ! -f "${NODE_PATH}/staking/POOL_ID" ]; then
echo "Missing required POOL_ID."
MISSING_FILES=1
fi
if [ -n "$MISSING_FILES" ]; then
echo "You are missing required files to start."
echo "You need to initialize the stake pool keys, addresses and certificates and submit them to the blockchain first."
echo "You can do that by running \`create_stakepool\`"
read
exit
else
tmux \
new-session "source /scripts/functions/run_stakingnode; run_stakingnode" \; \
split-window "source /scripts/functions/status; status" \; \
select-layout even-horizontal
fi

32
scripts/wallet_balance Normal file
View File

@ -0,0 +1,32 @@
#!/bin/bash
WALLET=$1
if [ -z "$WALLET" ]; then
echo "Invalid wallet."
MISSING_ARG=1
fi
if [ -n "$MISSING_ARG" ]; then
exit
fi
# Check for required files
if [ ! -f "${NODE_PATH}/staking/wallets/${WALLET}/payment.addr" ]; then
echo "Missing required payment.addr. You need to run \`generate_waller ${WALLET}\` to generate this key."
MISSING_FILES=1
fi
if [ -n "$MISSING_FILES" ]; then
exit
fi
# Wait for node to sync
if [[ "${WAIT_FOR_SYNC}" == "True" ]]; then
wait_for_sync 99.90
fi
ADDRESS=$(cat ${NODE_PATH}/staking/wallets/${WALLET}/payment.addr)
cardano-cli query utxo ${NETWORK_ARGUMENT} --allegra-era --address ${ADDRESS}

132
scripts/withdraw_rewards Normal file
View File

@ -0,0 +1,132 @@
#!/bin/bash
source /scripts/functions/check_balance
WALLET=$1
TIMESTAMP=$(date +%s)
if [ -z "$WALLET" ]; then
echo "Invalid wallet."
MISSING_ARG=1
fi
if [ -n "$MISSING_ARG" ]; then
exit
fi
# Check for required files
if [ ! -f "${NODE_PATH}/staking/wallets/${WALLET}/payment.skey" ]; then
echo "Missing required payment.skey. You need to run \`generate_waller ${WALLET}\` to generate this key."
MISSING_FILES=1
fi
if [ ! -f "${NODE_PATH}/staking/wallets/${WALLET}/payment.addr" ]; then
echo "Missing required payment.addr. You need to run \`generate_waller ${WALLET}\` to generate this key."
MISSING_FILES=1
fi
if [ ! -f "${NODE_PATH}/staking/wallets/${WALLET}/stake.addr" ]; then
echo "Missing required stake.addr. You need to run \`generate_waller ${WALLET}\` to generate this key."
MISSING_FILES=1
fi
if [ ! -f "${NODE_PATH}/staking/wallets/${WALLET}/stake.skey" ]; then
echo "Missing required stake.skey. You need to run \`generate_waller ${WALLET}\` to generate this key."
MISSING_FILES=1
fi
if [ -n "$MISSING_FILES" ]; then
exit
fi
cd ${NODE_PATH}/staking/wallets/${WALLET}/
mkdir -p transactions/
# Wait for node to sync
if [[ "${WAIT_FOR_SYNC}" == "True" ]]; then
wait_for_sync 99.90
fi
cardano-cli query protocol-parameters \
${NETWORK_ARGUMENT} --allegra-era \
--out-file ${NODE_PATH}/staking/protocol.json
ADDRESS=$(cat payment.addr)
STAKE_ADDRESS=$(cat stake.addr)
REWARD_BALANCE=$(cardano-cli query stake-address-info ${NETWORK_ARGUMENT} --allegra-era --address $(cat stake.addr) | jq -r ".[0].rewardAccountBalance")
check_balance 200000 # Dummy transaction fee
# Draft transaction
echo "Draft transaction"
cardano-cli transaction build-raw \
--tx-in "${UTXO}#${TXIX}" \
--tx-out ${ADDRESS}+0 \
--withdrawal ${STAKE_ADDRESS}+${REWARD_BALANCE} \
--ttl 0 \
--fee 0 \
--out-file transactions/tx.${TIMESTAMP}.draft
echo "Calculate fee"
FEE=$(cardano-cli transaction calculate-min-fee \
--tx-body-file transactions/tx.${TIMESTAMP}.draft \
--tx-in-count 1 \
--tx-out-count 1 \
${NETWORK_ARGUMENT} \
--witness-count 1 \
--byron-witness-count 0 \
--protocol-params-file ${NODE_PATH}/staking/protocol.json | tr ' ' '\n' | head -1)
# Find UTXO in address with enough lovelace to do the transaction
check_balance ${FEE}
# Update slot and TTL
SLOT=$(get_slot)
TTL=$(expr ${SLOT} + 500)
# Display transaction info
BALANCE_AFTER_TX=$(expr ${LOVELACE} + ${REWARD_BALANCE} - ${FEE})
echo "Creating rewards withdrawal transaction"
echo "Current tip Slot: ${SLOT}"
echo "TTL: ${TTL}"
echo "Withdrawing rewards from: ${STAKE_ADDRESS}"
echo "Withdrawing rewards to: ${ADDRESS}"
echo "Fee is: ${FEE} Lovelace"
echo "Rewards amount: ${REWARD_BALANCE} Lovelace"
echo "Lovelace before withdrawal: ${LOVELACE}"
echo "Lovelace after withdrawal: ${BALANCE_AFTER_TX}"
#
# Create the transaction
#
cardano-cli transaction build-raw \
--tx-in "${UTXO}#${TXIX}" \
--tx-out ${ADDRESS}+${BALANCE_AFTER_TX} \
--withdrawal ${STAKE_ADDRESS}+${REWARD_BALANCE} \
--ttl ${TTL} \
--fee ${FEE} \
--out-file transactions/tx.${TIMESTAMP}.raw
cardano-cli transaction sign \
--tx-body-file transactions/tx.${TIMESTAMP}.raw \
--signing-key-file payment.skey \
--signing-key-file stake.skey \
${NETWORK_ARGUMENT} \
--out-file transactions/tx.${TIMESTAMP}.signed
# Submit the transaction
read -n 1 -r -s -p $'Press enter to submit the transaction...\n'
echo "Submit transaction"
OUT=$(cardano-cli transaction submit \
--tx-file transactions/tx.${TIMESTAMP}.signed \
${NETWORK_ARGUMENT} 2>&1)
if [[ $OUT =~ "Error" ]]
then
echo "An error occoured."
echo ${OUT}
read
else
echo "Transaction has been submitted to the blockchain."
echo ${OUT}
fi