Skip to content
This repository was archived by the owner on Apr 8, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 50 additions & 15 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,21 @@

## Quick start
Binaries can be found [here](https://github.com/mintlayer/core/releases).

Running a node also requires as input a chain specification.
Currently a single chain specification for the testnet is provided, and can be downloaded using curl:

```
curl --proto '=https' -sSf \
https://raw.githubusercontent.com/mintlayer/core/master/assets/Testnet1Spec.json \
--output Testnet1Spec.json
```
Download and run:
```
mintlayer-core --base-path data/my_first_ml_node --validator --rpc-external --rpc-methods Unsafe --chain=Testnet1Spec.json
mintlayer-core \
--base-path data/my_first_ml_node \
--validator \
--chain=Testnet1Spec.json
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never used the --rpc-external and --rpc-methods Unsafe options so at least for basic usage, these are not necessary. The question is whether users should pass them by default. Ideally, the command to run the node should be as simple as possible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, the rpc-external flag binds to all network interfaces with IP 0.0.0.0, meaning that anyone can connect to the node from outside the network. And rpc-methods Unsafe, basically allows anyone connecting to the RPC to be an owner of the node, and hence, expose keys. Meaning: We're basically exposing everything to everyone and allowing anyone connecting to RPC to do whatever they want... what's the logic behind this?! Did we try not adding them and had problems?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the command to run as I understood it from Amin.
@zorvan What do you think of Lukas's and Sam's comments?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are right. Latest version of cli switches for user and production id reaped off from those.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zorvan so what is the correct command? Should I simply remove --rpc-external and --rpc-methods Unsafe?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in every issue in programming, that depends on what you want to do. The right solution, in my opinion, is to remove these and tell the user that they will be binding to localhost, hence, no connections from the outside will be possible and explain that this is a safety procedure and using tunnels is usually better than opening to the outside, and then explain that unsafe methods will not work unless the user enables them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And let me explain that hacks with externally accessible RPC happened before:

https://www.coindaily.co/2801-2/

```

to start a node. It will automatically connect to the Mintlayer bootnodes.
Expand Down Expand Up @@ -80,7 +92,7 @@ See [Mintlayer installation on Windows](windows_installation.md)
## Running a node
Clone the repository:

```bash
```
git clone https://github.com/mintlayer/core.git
```

Expand All @@ -94,25 +106,47 @@ to build the project.

Finally, to run a node:
```
RUST_LOG=info ./target/release/mintlayer-core --base-path [PATH_TO_DB] --name [NODE_NAME] --port [P2P_PORT] --ws-port [WEB_SOCKET_PORT] --rpc-port [RPC_PORT] --validator --rpc-methods Unsafe --chain=[CHAIN_SPEC]
RUST_LOG=info ./target/release/mintlayer-core \
--base-path [PATH_TO_DB] \
--name [NODE_NAME] \
--port [P2P_PORT] \
--ws-port [WEB_SOCKET_PORT] \
--rpc-port [RPC_PORT] \
--validator \
--chain=[CHAIN_SPEC]
```

For example,
```
RUST_LOG=info ./target/release/mintlayer-core --base-path data/node1 --name brian --port 30333 --ws-port 9945 --rpc-port 9933 --validator --rpc-methods Unsafe --chain=Testnet1Spec.json
RUST_LOG=info ./target/release/mintlayer-core \
--base-path data/node1 \
--name brian \
--port 30333 \
--ws-port 9945 \
--rpc-port 9933 \
--validator \
--chain=Testnet1Spec.json
```

Let's look at these flags in detail:

| <div style="min-width:110pt"> Flags </div> | Descriptions |
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--base-path` | Specifies a directory where Mintlayer should store all the data related to this chain. If the directory does not exist, it will be created for you. If other blockchain data already exists there you will get an error. Either clear the directory or choose a different one. |
| `--chain local` | Specifies which chain specification to use. There are a few prepackaged options including `local`, `development`, and `staging` but generally one specifies their own chain spec file. We'll specify our own file in a later step. |
| `--alice` | Puts the predefined Alice keys (both for block production and finalization) in the node's keystore. Generally one should generate their own keys and insert them with an RPC call. We'll generate our own keys in a later step. This flag also makes Alice a validator. |
| `--port 30333` | Specifies the port that your node will listen for p2p traffic on. `30333` is the default and this flag can be omitted if you're happy with the default. If Bob's node will run on the same physical system, you will need to explicitly specify a different port for it. |
| `--ws-port 9945` | Specifies the port that your node will listen for incoming WebSocket traffic on. The default value is `9944`. This example uses a custom web socket port number (`9945`). |
| `--rpc-port 9933` | Specifies the port that your node will listen for incoming RPC traffic on. `9933` is the default, so this parameter may be omitted. |
| `--node-key <key>` | The Ed25519 secret key to use for `libp2p` networking. The value is parsed as a hex-encoded Ed25519 32 byte secret key, i.e. 64 hex characters. WARNING: Secrets provided as command-line arguments are easily exposed. Use of this option should be limited to development and testing. |
| `--telemetry-url` | Tells the node to send telemetry data to a particular server. The one we've chosen here is hosted by Parity and is available for anyone to use. You may also host your own (beyond the scope of this article) or omit this flag entirely. |
| `--validator` | Means that we want to participate in block production and finalization rather than just sync the network. |
| <div style="min-width:110pt"> Flags </div> | Descriptions |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--base-path` | Specifies a directory where Mintlayer should store all the data related to this chain. If the directory does not exist, it will be created for you. If other blockchain data already exists there you will get an error. Either clear the directory or choose a different one. |
| `--chain=[CHAIN_SPEC_FILE]` | Specifies which chain specification to use. A chain specification, or "chain spec", is a collection of configuration information that dictates which network a blockchain node will connect to, which entities it will initially communicate with, and what consensus-critical state it must have at genesis. |
| `--alice` | Puts the predefined Alice keys (both for block production and finalization) in the node's keystore. Generally one should generate their own keys and insert them with an RPC call. We'll generate our own keys in a later step. This flag also makes Alice a validator. |
| `--port 30333` | Specifies the port that your node will listen for p2p traffic on. `30333` is the default and this flag can be omitted if you're happy with the default. If Bob's node will run on the same physical system, you will need to explicitly specify a different port for it. |
| `--ws-port 9945` | Specifies the port that your node will listen for incoming WebSocket traffic on. The default value is `9944`. This example uses a custom web socket port number (`9945`). |
| `--rpc-port 9933` | Specifies the port that your node will listen for incoming RPC traffic on. `9933` is the default, so this parameter may be omitted. |
| `--telemetry-url` | Tells the node to send telemetry data to a particular server. The one we've chosen here is hosted by Parity and is available for anyone to use. You may also host your own (beyond the scope of this article) or omit this flag entirely. |
| `--validator` | Means that we want to participate in block production and finalization rather than just sync the network. |

*Note*: As a safety precaution, the node will listen to RPC interfaces on localhost only.
It is possible expose the node's RPC port publicly `--rpc-external`, but only do this if you understand the risks involved. As a safer alternative to enable RPC calls from outside the node, consider using tunnels.

**TODO** Provide an explanation/examples of methods that are unsafe to call. Or link to a list, together with an explanation of why each method is unsafe.

*Note*: Some RPC calls can be used to control the node's behavior and should never (or rarely) be exposed. We call such methods _Unsafe_, and they are disabled by default. It is possible to enable them using `--rpc-methods Unsafe`.

## Docker setup

Expand All @@ -128,6 +162,7 @@ If you want to save the blockchain to host, run:
docker run -v ~/ml-blockchain:/tmp/ml-core -t mintlayer-core
```


## Create a chain specification

In the preceding example, we used `--chain local` which is a predefined "chain spec" that has Alice and Bob specified as validators along with many other useful defaults.
Expand Down
93 changes: 48 additions & 45 deletions docs/tokens.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
# Mintlayer Tokens
**TODO Do we want Rust code in this doc?**

Each transaction output must carry a data field. This field describes the purpose of the transaction.
This document describes the structure of transactions involving tokens on Mintlayer. Currently, two types of tokens are supported:

We must highlight the following at the moment:
1. *MLS-01 tokens*: MLS-01 is the "basic" Mintlayer token standard, analogous to, say, ERC-20 tokens on Ethereum.

- Transfer Tokens or NFT
- Token Issuance
- Burning tokens
- NFT creation
2. NFTs

A transaction involving transaction output carries a (possibly empty) `data` field specifying the purpose of the transaction.

All transactions must be signed on the client side. This means we cannot sign transactions on the node side.
**TODO what is the connection between these two sentences?**
In the future, there will be changes to the structures of transactions and we will be required to track them.
**TODO by structures above to we mean rust structs? Why is this interesting to the user?**
The data field can be any of the following:

- Transfer of MLS-01 tokens or NFTs
- Token issuance
- Token burning
- NFT creation

## Transfer Tokens
## Transferring Tokens

**TODO sentence fragment, I don't understand...**
**TODO When do we NOT use the TxData field?**
For transfering funds to another person in a given UTXO. To send MLT we will use the MLT token ID, which is equal to 0. If the token ID is equal to the ID of the MLS-01 (**TODO what is MLS-01**) token, then the amount of token is transferred to the recipient. The commission is taken only in MLT (**TODO what is this commission**. If the token ID is equal to the ID of any NFT, then the data of this NFT is transferred to the recipient without changing the creator field. The UTXO model itself allows to determine the owner of the NFT.
To send MLT we use the MLT token ID, which is equal to 0. If the token ID is equal to the ID of an MLS-01 token, then the amount of the token is transferred to the recipient. The transaction fee is taken only in MLT. If the token ID is equal to the ID of any NFT, then the data of this NFT is transferred to the recipient without changing the creator field. The UTXO model itself allows to determine the owner of the NFT.

```rust
TxData {
Expand All @@ -30,27 +28,32 @@ TxData {
}
```

## Issue Tokens
When issuing a new token, we specify the data for creating a new token in the transaction input, where the `token_id` is a hash of the inputs. **TODO which inputs?**
**TODO explain remaining fields**
## Issuing Tokens

**TODO understand the comment**
```rust
To issue a new token, we specify the data for creating the token in the transaction output's `data` field:

```rust
TxData {
TokenIssuanceV1 {
token_id: TokenID,
token_ticker: Vec<u8>,
amount_to_issue: Value,
// Should be not more than 18 numbers
number_of_decimals: u8,
metadata_URI: Vec<u8>,
}
token_ticker: Vec<u8>,
amount_to_issue: Value,
// Should not be more than 18
number_of_decimals: u8,
metadata_URI: Vec<u8>,
}
}
```
```

Here, `token_ticker` is a short name given to the token (up to 5 chararcters long).

The `metatdata_URI` is a web link to a JSON file where we can store additional information about the token

The _token ID_ is defined as a hash of the _first input_ of the issuance transaction.


### Burning Tokens

### Burn Tokens
**TODO verify - the input should be a utxo that contains tokens, the output should contain the TokenBurn arm**
A token burning - as an input is used by UTXO that contains tokens. As an output, the data field should contain the TokenBurn arm. If the amount in burning the output is less than in the input then there should exist at least one output for returning the funds change. In this case, you can burn any existing number of tokens. After this operation, you can use UTXO for the remaining amount of tokens.
The input for a token-burning transaction should be a UTXO containing tokens. In the output, the data field should contain the _TokenBurn_ variant. If the `amount_to_burn` in the output is less than the amount in the input, then there should exist at least one output for returning the difference. In this way, any existing number of tokens can be burned.

```rust
TxData {
Expand All @@ -61,18 +64,17 @@ TxData {
}
```
### NFT
TO DO
**TODO**

## Wallet
**TODO**

TO DO
## Issue and Transfer Tokens
## Issuing and Transferring Tokens

**TODO who are these examples meant for?**
```rust
/* Transfer and Issuance in one Tx */

// Alice issues 1_000_000_000 MLS-01, and send them to Karl
// Alice issues 1_000_000_000 MLS-01 tokens, and sends them to Karl
let (utxo0, input0) = tx_input_gen_no_signature();
let tx = Transaction {
inputs: vec![input0],
Expand All @@ -96,13 +98,17 @@ let tx = Transaction {
}
.sign_unchecked(&[utxo0.clone()], 0, &alice_pub_key);

let first_issuance_token_id = TokenId::new(&tx.inputs[0]);
assert_ok!(Utxo::spend(Origin::signed(H256::zero()), tx.clone()));

let first_issuance_token_id = TokenId::new(&tx.inputs[0]);

// The newly issued token is represented by the TransactionOutput at index 1
// "Outoint" here refers to the hash of the TransactionOutput struct.
let token_utxo_hash = tx.outpoint(1);
let token_utxo = tx.outputs[1].clone();


// Let's send 300_000_000 and rest back and create another token
// Let's send alice 300_000_000 and the rest back to Karl, andalso create another token, "KarlToken"
let tx = Transaction {
inputs: vec![TransactionInput::new_empty(token_utxo_hash)],
outputs: vec![
Expand All @@ -126,7 +132,7 @@ let tx = Transaction {
0,
H256::from(karl_pub_key),
OutputData::TokenIssuanceV1 {
token_ticker: "Token".as_bytes().to_vec(),
token_ticker: "KarlToken".as_bytes().to_vec(),
amount_to_issue: 5_000_000_000,
// Should be not more than 18 numbers
number_of_decimals: 12,
Expand All @@ -137,19 +143,20 @@ let tx = Transaction {
time_lock: Default::default(),
}
.sign_unchecked(&[token_utxo.clone()], 0, &karl_pub_key);

assert_ok!(Utxo::spend(Origin::signed(H256::zero()), tx.clone()));

let alice_transfer_utxo_hash = tx.outpoint(0);
let karl_transfer_utxo_hash = tx.outpoint(1);
let karl_issuance_utxo_hash = tx.outpoint(2);

assert!(!UtxoStore::<Test>::contains_key(H256::from(
token_utxo_hash
)));
assert!(UtxoStore::<Test>::contains_key(alice_transfer_utxo_hash));
assert!(UtxoStore::<Test>::contains_key(karl_transfer_utxo_hash));
assert!(UtxoStore::<Test>::contains_key(karl_issuance_utxo_hash));



// Let's check token transfer
UtxoStore::<Test>::get(alice_transfer_utxo_hash)
.unwrap()
Expand All @@ -165,8 +172,6 @@ UtxoStore::<Test>::get(alice_transfer_utxo_hash)
})
.unwrap();



UtxoStore::<Test>::get(karl_transfer_utxo_hash)
.unwrap()
.data
Expand All @@ -181,8 +186,6 @@ UtxoStore::<Test>::get(karl_transfer_utxo_hash)
})
.unwrap();



// Let's check token issuance
UtxoStore::<Test>::get(karl_issuance_utxo_hash)
.unwrap()
Expand Down
Loading