├── .editorconfig ├── .github ├── CODEOWNERS ├── FEATURE_REQUEST.md ├── ISSUE_TEMPLATE.md └── workflows │ └── build.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── SECURITY.md ├── assets ├── Testnet1Spec.json ├── bootnodes.json ├── functional_test_keys.json └── test_keys.json ├── doc ├── rust-setup.md └── tx-sign.md ├── docker-compose.yml ├── docs ├── README.md ├── key_management.md ├── rewards.md ├── staking.md ├── tokens.md ├── transaction.md └── windows_installation.md ├── libs ├── base58_nostd │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── bech32 │ ├── Cargo.toml │ ├── README.md │ └── src │ │ └── lib.rs └── chainscript │ ├── Cargo.toml │ ├── LICENSE │ ├── README.md │ └── src │ ├── context.rs │ ├── error.rs │ ├── interpreter.rs │ ├── lib.rs │ ├── opcodes.rs │ ├── script.rs │ ├── sighash.rs │ └── util.rs ├── node ├── Cargo.toml ├── build.rs └── src │ ├── chain_spec.rs │ ├── cli.rs │ ├── command.rs │ ├── lib.rs │ ├── main.rs │ ├── rpc.rs │ └── service.rs ├── pallets ├── pp │ ├── Cargo.toml │ ├── LICENSE │ ├── README.md │ └── src │ │ ├── benchmarking.rs │ │ ├── lib.rs │ │ ├── mock.rs │ │ └── tests.rs ├── template │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── benchmarking.rs │ │ ├── lib.rs │ │ ├── mock.rs │ │ └── tests.rs └── utxo │ ├── Cargo.toml │ ├── LICENSE │ ├── README.md │ ├── rpc │ ├── Cargo.toml │ ├── README.md │ ├── runtime-api │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── src │ │ └── lib.rs │ └── src │ ├── benchmarking.rs │ ├── lib.rs │ ├── mock.rs │ ├── rewards.rs │ ├── script.rs │ ├── sign.rs │ ├── staking.rs │ ├── staking_tests.rs │ ├── tests.rs │ ├── tokens.rs │ └── weights.rs ├── runtime ├── Cargo.toml ├── build.rs └── src │ ├── lib.rs │ └── staking.rs ├── rustfmt.toml ├── scripts ├── docker_run.sh ├── init.sh └── wallet.py ├── template.rs ├── test ├── README.md ├── config.ini.in └── functional │ ├── code.wasm │ ├── custom-types.json │ ├── example_test.py │ ├── feature_alice_bob_test.py │ ├── feature_smart_contract_test.py │ ├── feature_staking_diff_addresses.py │ ├── feature_staking_extra.py │ ├── feature_staking_extra_not_validator.py │ ├── feature_staking_extra_wrong_controller.py │ ├── feature_staking_first_time.py │ ├── feature_staking_less_than_minimum.py │ ├── feature_staking_unlock_and_withdraw.py │ ├── feature_staking_unlock_not_validator.py │ ├── feature_staking_withdraw_no_unlock.py │ ├── feature_staking_withdraw_not_validator.py │ ├── metadata.json │ ├── test_framework │ ├── __init__.py │ ├── address.py │ ├── bignum.py │ ├── messages.py │ ├── mintlayer │ │ ├── __init__.py │ │ ├── _staking.py │ │ ├── contract.py │ │ └── utxo.py │ ├── script.py │ ├── test_framework.py │ ├── test_node.py │ └── util.py │ └── test_runner.py └── traits ├── pp-api ├── Cargo.toml └── src │ └── lib.rs └── utxo-api ├── Cargo.toml └── src └── lib.rs /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = lf 3 | 4 | [*.rs] 5 | indent_style = space 6 | indent_size = 4 7 | max_line_length = 100 8 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @muursh @erubboli @iljakuklic @zorvan @TheQuantumPhysicist 2 | -------------------------------------------------------------------------------- /.github/FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | __Is your feature request related to a problem? Please describe.__ A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 2 | 3 | __Describe the solution you'd like__ A clear and concise description of what you want to happen. 4 | 5 | __Describe alternatives you've considered__ A clear and concise description of any alternative solutions or features you've considered. 6 | 7 | __Additional context__ Add any other context or screenshots about the feature request here. 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | __Describe the bug__ A clear and concise description of what the bug is. 2 | 3 | __To Reproduce Steps to reproduce the behavior__: 4 | 5 | __Expected behavior__ A clear and concise description of what you expected to happen. 6 | 7 | __Environment__ A concise description of your environment: Operating system, rust version, Mintlayer version, specific commit 8 | 9 | __Additional context__ Add any other context about the problem here. 10 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | 2 | name: build 3 | 4 | on: 5 | pull_request: 6 | branches: 7 | - master 8 | - staging 9 | 10 | env: 11 | CARGO_TERM_COLOR: always 12 | 13 | jobs: 14 | check_l: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Install nightly 19 | uses: actions-rs/toolchain@v1 20 | with: 21 | profile: minimal 22 | toolchain: nightly-2021-08-01 23 | target: wasm32-unknown-unknown 24 | components: rustfmt 25 | default: true 26 | - name: Checkout repository and submodules 27 | uses: actions/checkout@v2 28 | with: 29 | submodules: recursive 30 | - name: CheckL 31 | run: cargo check 32 | 33 | check_m: 34 | runs-on: macos-latest 35 | steps: 36 | - uses: actions/checkout@v2 37 | - name: Install nightly 38 | uses: actions-rs/toolchain@v1 39 | with: 40 | profile: minimal 41 | toolchain: nightly-2021-08-01 42 | target: wasm32-unknown-unknown 43 | components: rustfmt 44 | default: true 45 | - name: Checkout repository and submodules 46 | uses: actions/checkout@v2 47 | with: 48 | submodules: recursive 49 | - name: CheckL 50 | run: cargo check 51 | 52 | build: 53 | runs-on: ubuntu-latest 54 | # if: github.ref == 'refs/heads/master' 55 | steps: 56 | - uses: actions/checkout@v2 57 | - name: Install nightly 58 | uses: actions-rs/toolchain@v1 59 | with: 60 | profile: minimal 61 | toolchain: nightly-2021-08-01 62 | target: wasm32-unknown-unknown 63 | components: rustfmt 64 | default: true 65 | - name: Checkout repository and submodules 66 | uses: actions/checkout@v2 67 | with: 68 | submodules: recursive 69 | - name: Build 70 | run: cargo build --release 71 | - name: Run tests 72 | run: cargo test --release 73 | - name: Prepare functional tests 74 | uses: actions/setup-python@v2 75 | with: 76 | python-version: '3.9' 77 | - name: Install substrate-interface 78 | run: python -m pip install 'substrate-interface == 0.13.12' 79 | - name: Install scalecodec 80 | run: python -m pip install 'scalecodec == 0.11.18' 81 | - name: Run functional tests 82 | run: python test/functional/test_runner.py 83 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | **/target/ 4 | # These are backup files generated by rustfmt 5 | **/*.rs.bk 6 | 7 | .DS_Store 8 | 9 | # Intellij IDEA 10 | .idea/ 11 | *.iml 12 | /customSpec.json 13 | 14 | # VSCode 15 | .vscode/ 16 | 17 | # Test Python cache 18 | test/**/__pycache__ 19 | 20 | # Files generated for the testing system 21 | test/config.ini 22 | 23 | # The cache for docker container dependency 24 | .cargo 25 | 26 | # The cache for chain data in container 27 | .local 28 | 29 | # direnv cache 30 | .direnv 31 | 32 | # Python compiled files 33 | *.pyc 34 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | This project adheres to No Code of Conduct. We are all adults. We accept anyone's contributions. Nothing else matters. 4 | 5 | For more information please visit the [No Code of Conduct](https://github.com/domgetter/NCoC) homepage. 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Mintlayer core contributing guide 2 | 3 | We are happy to take contributions to the project in any form: if you find a bug feel free to create an issue, if you fix a bug feel free to create a pr to merge your fix, if you want to add a totally new feature go ahead and do so. 4 | 5 | 6 | ## Setup 7 | 8 | Mintlayer is built using Substrate which means you'll need Rust and Substrate set up to do any development work. The functional tests require Python to be installed too. 9 | 10 | You can follow these steps below or go Substrate's own guide [here](https://docs.substrate.io/v3/getting-started/overview/) 11 | ### Build essentials 12 | 13 | #### Ubuntu 14 | sudo apt update 15 | sudo apt install -y git clang curl libssl-dev llvm libudev-dev 16 | 17 | #### Fedora 18 | sudo dnf update 19 | sudo dnf install clang curl git openssl-devel 20 | 21 | #### Arch 22 | pacman -Syu --needed --noconfirm curl git clang 23 | 24 | #### MacOS (Note there are issues with M1 processors - you're on your own for now :D) 25 | brew update 26 | brew install openssl 27 | 28 | 29 | ### Rust 30 | curl https://sh.rustup.rs -sSf | sh 31 | source ~/.cargo/env 32 | rustup default stable 33 | rustup update 34 | rustup update nightly 35 | rustup target add wasm32-unknown-unknown --toolchain nightly 36 | 37 | ### Functional test stuff 38 | Ensure python3 is already installed. I'll be shocked if it isn't. After that install the dependencies listed below. 39 | 40 | python -m pip install 'substrate-interface == 0.13.12' 41 | python -m pip install 'scalecodec == 0.11.18' 42 | 43 | ## Building Mintlayer 44 | 45 | To build Mintlayer go to [the main repo](https://github.com/mintlayer/core) and clone the repo using git like you would with any other repo. 46 | Development happens on the staging branch so make sure you can build Mintlayer by checking out the staging branch and building the codebase. 47 | 48 | git fetch --all 49 | git checkout staging 50 | cargo build 51 | 52 | The above will build the code base in debug mode. If you go to `target/debug` you should find the `mintlayer-core` binary. If you have issues building it's probably 53 | the installation steps above, double-check them and try again. If the build keeps failing then feel free to reach out to us in an issue or on [discord](https://discord.gg/XMrhvngQ8T). 54 | 55 | If that all goes swimmingly then it's time to do something very very slightly more exciting. Make sure you can run the unit tests using `cargo test` 56 | 57 | Yep wasn't that exciting. All of those tests should pass, if they don't feel free to dig in and find out what's going on. 58 | 59 | To build a release version of Mintlayer you simply run `cargo build --release` 60 | 61 | To run the functional tests, ensure Mintlayer has been compiled first, go to `test` and run `test_runner.py`. Everything else will happen automatically. 62 | 63 | ## How to actually contribute 64 | 65 | The first thing to do, once you know what you want to do, is to open an issue. If you think you'd found a bug open an issue so it can be discussed with the wider 66 | community. If you think you've got a snazzy new idea for a feature, open an issue and we'll discuss it as a community; maybe someone else is already working on it... 67 | 68 | Whatever it is you're working on you'll want to create a branch for your bug fix or feature from staging 69 | 70 | 71 | git checkout staging 72 | git checkout -b my_new_branch 73 | 74 | 75 | I'd suggest you pick a better name than that though, something which makes it obvious what you're working on is preferred. Once you're done the first step is to make 76 | sure that the existing functional tests and unit tests still work. If you've broken something it's time to go and fix that first. Once the existing tests are good 77 | it's time for you to add your own. Even for small bug fixes adding a unit test is worth the effort to ensure the bug isn't reintroduced later. For new features, functional tests 78 | are a hard requirement. Make life as easy as possible for the reviewer when they have to look at the actual code. What testing have you done? Have you run any benchmarks? 79 | 80 | Once you've created a set of tests that prove out your code create a PR to merge your branch into staging. Make sure you write a good PR. Explain what you're doing, 81 | explain why you're doing it, explain how this interacts with the existing codebase and explain how it works. Make sure to link to the open issue too. When you pick 82 | reviewers GitHub will likely recommend some people. If not tag anyone and they can help get the right people involved. Your code will either be merged or changes will be requested. 83 | Before you open the PR, think about what else you can do to make the reviewer's life easier… Can you run cargo-audit to find known issues in libraries? Could you run a fuzzer or static analyser? Have you checked the licenses of any libraries you’re using? 84 | A good pull request should try and limit the number of lines changed in the request, as a general rule it takes roughly 60 mins to review a 300-400 line request so try and keep PRs to 300-400 lines in total. 85 | A pull request should try and deal with a single issue be it a new feature or a bug fix. If you’re fixing 2 separate unrelated bugs then open 2 PRs. A PR should be made of logical commits, that could be a single commit for a simple bug or several commits for a more complex new feature. If you refactor some existing code and add a new feature in the same PR then that should be at least 2 commits. 86 | 87 | 88 | ## A quick guide to Mintlayer 89 | 90 | In the libs dir you'll find the chainscript and bech32 code. Chainscript is Mintlayer's implementation of bitcoinscript, they're not quite identical but they are 91 | pretty similar. You'll find some links to docs on chainscript [here](https://github.com/mintlayer/core/tree/master/libs/chainscript). 92 | 93 | Mintlayer uses a UTXO system rather than an account-based system you can find the implementation of the UTXO system [here](https://github.com/mintlayer/core/tree/master/pallets/utxo). 94 | 95 | Mintlayer has a feature known as programmable pools (or PPs). These are essentially Wasm-based smart contracts. As it stands PP support is very much a work in progress. 96 | 97 | At the moment Mintlayer uses Schnorr signatures for its base crypto. There is an intention to move to BLS in the near future. We have a BLS implementation ready to go but there is some degree of work to be done to fully integrate it with the existing code base, if you create a new feature try to plan it in a cryptographically agnostic way. 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [profile.release] 2 | panic = 'unwind' 3 | 4 | [workspace] 5 | members = [ 6 | 'node', 7 | 'libs/*', 8 | 'pallets/*', 9 | 'runtime', 10 | ] 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 RBB S.r.l 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mintlayer core 2 | 3 | ## NOTE THIS REPO IS NOT LONGER UNDER ACTIVE DEVELOPMENT GO TO [OUR NEW REPO](https://github.com/mintlayer/mintlayer-core) 4 | 5 | https://www.mintlayer.org/ 6 | 7 | For a more technical introduction to Mintlayer visit [our docs](https://docs.mintlayer.org/). 8 | 9 | A draft of the consensus paper can be found [here](https://www.mintlayer.org/docs/DSA-consensus-paper-draft.pdf). 10 | 11 | ## Security issues 12 | If you find an issue related to the security of Mintlayer then please contact us at security@mintlayer.org so we can address the issue. Mintlayer has a [bug bounty program](https://www.mintlayer.org/bug-bounties) so if your security issue is valid you are elligble for a reward paid in MLT. Do not disclose the security issue publicly until the core Mintlayer team has agreed the issue can be disclosed. See [SECURITY.md](https://github.com/mintlayer/core/blob/master/SECURITY.md) for more info. 13 | 14 | ## Bugs 15 | Non-security related bugs should be opened as [issues](https://github.com/mintlayer/core/issues/new) in the core Mintlayer repo. Give as much detail as possible. If you want to fix a bug then see our guidelines for [contributing](https://github.com/mintlayer/core/blob/master/CONTRIBUTING.md). 16 | 17 | ## How to build and run Mintlayer 18 | 19 | ### Rust Setup 20 | 21 | First, complete the [basic Rust setup instructions](https://github.com/mintlayer/core/blob/master/doc/rust-setup.md). 22 | 23 | ### Run 24 | 25 | Use Rust's native `cargo` command to build and launch the template node: 26 | 27 | ```sh 28 | cargo run --release -- --dev --tmp 29 | ``` 30 | 31 | ### Build 32 | 33 | The `cargo run` command will perform an initial build. Use the following command to build the node 34 | without launching it: 35 | 36 | ```sh 37 | cargo build --release 38 | ``` 39 | or 40 | 41 | `cargo build` to build a debug version 42 | 43 | to purge the local chain run `./target/release/mintlayer-core purge-chain --dev` 44 | 45 | ### Docs 46 | 47 | Once the project has been built, the following command can be used to explore all parameters and 48 | subcommands: 49 | 50 | ```sh 51 | ./target/release/mintlayer-core -h 52 | ``` 53 | 54 | You can also find docs in the docs directory and within the directory for a specific pallet or lib. 55 | 56 | 57 | ### Single-Node Development Chain 58 | 59 | This command will start the single-node development chain with persistent state: 60 | 61 | ```bash 62 | ./target/release/mintlayer-core --dev 63 | ``` 64 | 65 | Purge the development chain's state: 66 | 67 | ```bash 68 | ./target/release/mintlayer-core purge-chain --dev 69 | ``` 70 | 71 | Start the development chain with detailed logging: 72 | 73 | ```bash 74 | RUST_LOG=debug RUST_BACKTRACE=1 ./target/release/mintlayer-core -lruntime=debug --dev 75 | ``` 76 | 77 | ### Connect with Polkadot-JS Apps Front-end 78 | 79 | Once the node template is running locally, you can connect it with **Polkadot-JS Apps** front-end 80 | to interact with your chain. [Click here](https://polkadot.js.org/apps/#/explorer?rpc=ws://localhost:9944) connecting the Apps to your local node template. 81 | 82 | ### Connect with Mintlayer's UI 83 | TODO 84 | 85 | ### Multi-Node Local Testnet 86 | 87 | If you want to see the multi-node consensus algorithm in action, refer to 88 | [our Start a Private Network tutorial](https://substrate.dev/docs/en/tutorials/start-a-private-network/). 89 | 90 | ## Project Structure 91 | 92 | ### Node 93 | 94 | - Networking: Mintlayer uses [libp2p](https://libp2p.io/) as its native networking stack for all inter-node communication. 95 | - Bootnodes: Mintlayer has [bootnodes](https://github.com/mintlayer/core/blob/master/assets/bootnodes.json) that a new node will attempt to boot to unless a specific node is specified by the user 96 | - Consensus: Mintlayer uses [AURA](https://docs.rs/sc-consensus-aura/0.9.0/sc_consensus_aura/) as its base consensus algorithm for the time being. There will be an update to introduce [DSA](https://www.mintlayer.org/docs/DSA-consensus-paper-draft.pdf) in the future but DSA is still in development. 97 | - Finality: Since we are using AURA for our consensus we currently rely on [GRANDPA](https://docs.rs/sc-finality-grandpa/0.9.0/sc_finality_grandpa/) for finality. 98 | - Chain Spec: You can find our chain specification in [chain_spec.rs](https://github.com/mintlayer/core/blob/master/node/src/chain_spec.rs). It defines the basics of the chain such as the genesis block and the bootnodes. 99 | - Services: [service.rs](https://github.com/mintlayer/core/blob/master/node/src/service.rs) defines the node implementation itself. It is here you'll find the consensus setup. 100 | 101 | 102 | ### Runtime 103 | 104 | For more information on what a [runtime](https://substrate.dev/docs/en/knowledgebase/getting-started/glossary#runtime) is follow the link. 105 | Code in the runtime must be written in `no_std` Rust since it compiles to Wasm. 106 | 107 | - lib.rs: The main file in Mintlayer's runtime. Here you'll find the Mintlayer specific code for block production such as the block production period. 108 | - staking.rs: Here you'll find Mintlayer's staking implementation. 109 | 110 | 111 | ### Pallets 112 | 113 | Mintlayer relies on a host of Substrate pallets and a few Mintlayer specific pallets. 114 | 115 | - pp: The implementation of programmable pools on Mintlayer. Essentially Wasm smart contracts 116 | - utxo: Mintlayer's UTXO system 117 | 118 | ### Libs 119 | 120 | Libs is home to code that is code that Mintlayer relies on but isn't technically a pallet. 121 | 122 | - chainscript: Mintlayer's bitcoin script implementation. 123 | - bech32: code for handling transactions with destinations encoded using bech32 124 | 125 | ### Testing 126 | 127 | You'll find unit tests littered throughout the codebase but the test directory is home to the functional test framework which is heavily based on Bitcoin's functional test framework. 128 | 129 | ### Crypto 130 | As it stands Mintlayer uses Schnorr for all crypto-related things. There is a plan to move to our BLS implementation in the near future but this, as it stands, is a work in progress. 131 | 132 | ### Contributing 133 | [See this guide](https://github.com/mintlayer/core/blob/master/CONTRIBUTING.md) 134 | 135 | ### Branches 136 | The key branches are master and staging. Master is used for fully tested code, staging is used as the development branch. Fixes or features should be created on new branches branched from staging. A PR is then created to merge the branch into staging where it will require a review from a member of the Mintlayer team. To merge into master create a PR to merge staging to master, a review is required and CI will run. Only select people have push access to master. 137 | 138 | ### Firewall rules 139 | 140 | The node uses TCP port 30333 for communications, this needs to be opened if you want to allow 141 | inbound connections. 142 | 143 | Using UFW: 144 | `sudo ufw allow 30333/tcp` 145 | 146 | Using iptables: 147 | `sudo iptables -A INPUT -p tcp --dport 30333 -j ACCEPT` 148 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | Mintlayer runs a responsible disclosure program for security issues, as such all security issues should be reported to security@mintlayer.org or ben@mintlayer.org. 2 | If you disclose a valid security issue then you may be eligble for a bounty paid in MLT see the details [here](https://www.mintlayer.org/bug-bounties/). 3 | 4 | It's best to err on the side of caution, if you find something you think is security related but not eligible for the bounty or something you're not 100% sure about then let us know on the above email addresses anyway as we treat each report on a report by report basis so you may still be paid a bounty. 5 | 6 | GPG keys for members for those you may speak to regarding security issues can be found on Mintlayer's [team page](https://www.mintlayer.org/about/), if the person has a key by their name then they could reply to you. If you click on the key you'll find their GPG key. 7 | 8 | Security issues may not be publicly announced until Mintlayer agrees. 9 | -------------------------------------------------------------------------------- /assets/bootnodes.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": [ 3 | "/ip4/18.222.224.28/tcp/30333/p2p/12D3KooWRn14SemPVxwzdQNg8e8Trythiww1FWrNfPbukYBmZEbJ", 4 | "/ip4/18.191.161.217/tcp/30333/p2p/12D3KooWE3kBRAnn6jxZMdK1JMWx1iHtR1NKzXSRv5HLTmfD9u9c", 5 | "/ip4/18.220.98.72/tcp/30333/p2p/12D3KooWGK4RzvNeioS9aXdzmYXU3mgDrRPjQd8SVyXCkHNxLbWN", 6 | "/ip4/18.191.188.167/tcp/30333/p2p/12D3KooWQCBAdAtvf67tds9m3kgDEXQb7hYwcNZVzBNE15jTEVeS", 7 | "/ip4/3.144.201.81/tcp/30333/p2p/12D3KooWLMc4NuFvnY5ahLdmX35YmVhV38vKDuvEp4y5Zsc2occh" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /assets/functional_test_keys.json: -------------------------------------------------------------------------------- 1 | { 2 | "users": [ 3 | { 4 | "name": "Alice", 5 | "sr25519_public_controller": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d", 6 | "sr25519_public_stash": "0xbe5ddb1579b72e84524fc29e78609e3caf42e85aa118ebfe0b0ad404b5bdd25f", 7 | "ed25519_public": "0x88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee" 8 | }, 9 | { 10 | "name": "Bob", 11 | "sr25519_public_controller": "0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48", 12 | "sr25519_public_stash": "0xfe65717dad0447d715f660a0a58411de509b42e6efb8375f562f58a554d5860e", 13 | "ed25519_public": "0xd17c2d7823ebf260fd138f2d7e27d114c0145d968b5ff5006125f2414fadae69" 14 | }, 15 | { 16 | "name": "Charlie", 17 | "sr25519_public_controller": "0x90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22", 18 | "sr25519_public_stash": "0x1e07379407fecc4b89eb7dbd287c2c781cfb1907a96947a3eb18e4f8e7198625", 19 | "ed25519_public": "0x439660b36c6c03afafca027b910b4fecf99801834c62a5e6006f27d978de234f" 20 | }, 21 | { 22 | "name": "Dave", 23 | "sr25519_public_controller": "0x306721211d5404bd9da88e0204360a1a9ab8b87c66c1bc2fcdd37f3c2222cc20", 24 | "sr25519_public_stash": "0xe860f1b1c7227f7c22602f53f15af80747814dffd839719731ee3bba6edc126c", 25 | "ed25519_public": "0x5e639b43e0052c47447dac87d6fd2b6ec50bdd4d0f614e4299c665249bbd09d9" 26 | }, 27 | { 28 | "name": "Erin", 29 | "sr25519_public_controller": "0xe659a7a1628cdd93febc04a4e0646ea20e9f5f0ce097d9a05290d4a9e054df4e", 30 | "sr25519_public_stash": "0x8ac59e11963af19174d0b94d5d78041c233f55d2e19324665bafdfb62925af2d", 31 | "ed25519_public": "0x1dfe3e22cc0d45c70779c1095f7489a8ef3cf52d62fbd8c2fa38c9f1723502b5" 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /assets/test_keys.json: -------------------------------------------------------------------------------- 1 | { 2 | "users": [ 3 | { 4 | "name": "Alice", 5 | "sr25519_public_controller": "0xba04ce6f11a1a73d5a8286446baa63671bf02eb9d2d896b5093b1b00ec9a6039", 6 | "sr25519_public_stash": "0xe8aee020dff3bf215aad934ea22d38cb64079581480dcf50573758cac29a8147", 7 | "ed25519_public": "0x7d17c5b414545a11d63237ccabadbda97a0fd6d1946405b105f8361338ed14ce" 8 | }, 9 | { 10 | "name": "Bob", 11 | "sr25519_public_controller": "0x64a76e4603735144eaf30b7343565a4e5adf752f26e3096c58daa47723179855", 12 | "sr25519_public_stash": "0x7e2cb3ed66cbd412203f41d29577f6a69ca3cba05ff026022c646d8118ee1708", 13 | "ed25519_public": "0x3d5e4f7b55d3e2487358961cd55297639bc459b1c0b632b3097ee8d9633847bc" 14 | }, 15 | { 16 | "name": "Charlie", 17 | "sr25519_public_controller": "0x8cb53fc2aa9b8bcc976537dd2b05a09a40f2929cfcef11014e608cc667dba60a", 18 | "sr25519_public_stash": "0x042a16e8cd2702d1808d8fe1adedbb8e0ca6f33a56c5681d9bc9f48b478a6651", 19 | "ed25519_public": "0x5f821a3eb5e4079582b7b936a32640f1546b6bc8ff10c7b602919959b0f54820" 20 | }, 21 | { 22 | "name": "Dave", 23 | "sr25519_public_controller": "0xf81245c610127ca6cf4a6ea41580a7a0ed7553a115728a97f29a9a25534ba202", 24 | "sr25519_public_stash": "0x56b2ce9c488bb1cdb1fb713e971aa68654783c9d6ccaca7572f4239fb300833e", 25 | "ed25519_public": "0x9d60dcd1d5d5418473dc9b20721063d86e12385871899add7a7078093993f922" 26 | }, 27 | { 28 | "name": "Erin", 29 | "sr25519_public_controller": "0x9eff4160f35aefab5574169eea8a9ce46078d808ce0e51fc9dbc774083758545", 30 | "sr25519_public_stash": "0xb6c13894c3f920624bac58da3dadbeec678350dcc6548de9b0ca36cc4b819722", 31 | "ed25519_public": "0x93b4f09a45fafdbe3acff66a9500f86d3792735b37ba1aa3907cd909634c92fe" 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /doc/rust-setup.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installation 3 | --- 4 | 5 | This page will guide you through the steps needed to prepare a computer for development with the 6 | Substrate Node Template. Since Substrate is built with 7 | [the Rust programming language](https://www.rust-lang.org/), the first thing you will need to do is 8 | prepare the computer for Rust development - these steps will vary based on the computer's operating 9 | system. Once Rust is configured, you will use its toolchains to interact with Rust projects; the 10 | commands for Rust's toolchains will be the same for all supported, Unix-based operating systems. 11 | 12 | ## Unix-Based Operating Systems 13 | 14 | Substrate development is easiest on Unix-based operating systems like macOS or Linux. The examples 15 | in the Substrate [Tutorials](https://substrate.dev/tutorials) and [Recipes](https://substrate.dev/recipes/) 16 | use Unix-style terminals to demonstrate how to interact with Substrate from the command line. 17 | 18 | ### macOS 19 | 20 | Open the Terminal application and execute the following commands: 21 | 22 | ```bash 23 | # Install Homebrew if necessary https://brew.sh/ 24 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" 25 | 26 | # Make sure Homebrew is up-to-date, install openssl and cmake 27 | brew update 28 | brew install openssl cmake 29 | ``` 30 | 31 | ### Ubuntu/Debian 32 | 33 | Use a terminal shell to execute the following commands: 34 | 35 | ```bash 36 | sudo apt update 37 | # May prompt for location information 38 | sudo apt install -y cmake pkg-config libssl-dev git build-essential clang libclang-dev curl 39 | ``` 40 | 41 | ### Arch Linux 42 | 43 | Run these commands from a terminal: 44 | 45 | ```bash 46 | pacman -Syu --needed --noconfirm cmake gcc openssl-1.0 pkgconf git clang 47 | export OPENSSL_LIB_DIR="/usr/lib/openssl-1.0" 48 | export OPENSSL_INCLUDE_DIR="/usr/include/openssl-1.0" 49 | ``` 50 | 51 | ### Fedora/RHEL/CentOS 52 | 53 | Use a terminal to run the following commands: 54 | 55 | ```bash 56 | # Update 57 | sudo dnf update 58 | # Install packages 59 | sudo dnf install cmake pkgconfig rocksdb rocksdb-devel llvm git libcurl libcurl-devel curl-devel clang 60 | ``` 61 | 62 | ## Rust Developer Environment 63 | 64 | This project uses [`rustup`](https://rustup.rs/) to help manage the Rust toolchain. First install 65 | and configure `rustup`: 66 | 67 | ```bash 68 | # Install 69 | curl https://sh.rustup.rs -sSf | sh 70 | # Configure 71 | source ~/.cargo/env 72 | ``` 73 | 74 | Finally, configure the Rust toolchain: 75 | 76 | ```bash 77 | rustup default stable 78 | rustup update nightly 79 | rustup update stable 80 | rustup target add wasm32-unknown-unknown --toolchain nightly 81 | ``` 82 | -------------------------------------------------------------------------------- /doc/tx-sign.md: -------------------------------------------------------------------------------- 1 | # Signing Transactions 2 | 3 | This document defines the serialization format used to obtain message used to sign transactions or 4 | verify transaction signatures in Mintlayer's UTXO model. 5 | 6 | ## Definitions and notation 7 | 8 | Constants `SIGHASH_*` have the same values as in Bitcoin 9 | 10 | `hash(x)`: a 256-bit BLAKE2 hash of the SCALE serialization of `x` 11 | 12 | `seq[i]` gives `i`-th element of a sequence 13 | 14 | `x.field` access a struct field 15 | 16 | `seq.*field`: given a vector `seq`, this is equivalent to Python pseudo-code `[ x.field for x in seq ]` 17 | 18 | ## Pubkey Format 19 | 20 | The first byte determines signature scheme used for this public key. 21 | The key itself immediately follows. 22 | 23 | * If signature type is: 24 | * Schnorr: 25 | * [1B] constant `0x00` 26 | * [32B] Schnorr pubkey 27 | 28 | ## Signature Format 29 | 30 | Different signature schemes have different signature sizes. 31 | 32 | * [`N` Bytes] signature 33 | * The length `N` is determined by corresponding pubkey type 34 | * If `sighash` is: 35 | * 0x00 (default): 36 | * [0B] nothing 37 | * otherwise: 38 | * [1B] sighash 39 | 40 | ## Message Format 41 | 42 | Given: 43 | 44 | * `tx`: transaction 45 | * `index`: the index of input curretnly under consideration 46 | * `sighash`: signature mode (1 byte) 47 | * `input_utxos`: a sequence of UTXOs being spent by transaction inputs 48 | * `index` < `input_utxos.len()` = `tx.inputs.len()` 49 | * `codesep_pos`: 4-byte position of the last `OP_CODESEPARATOR` 50 | * position is in number of decoded instructions (executed or not) 51 | * or `0xffffffff` if no `OP_CODESEPARATOR` has been seen so far 52 | or we are outside of a script context (e.g. plain pay to pubkey, no script involved) 53 | * `time_lock`: time lock (8 bytes unsigned number) 54 | * Number of blocks if `time_lock` < 500,000,000 55 | * Unix timestamp in seconds otherwise 56 | 57 | The message is a concatenation of: 58 | 59 | * [1B] sighash 60 | * If `sighash & SIGHASH_ANYONECANPAY` is: 61 | * 0: 62 | * [1B] constant `0x00` 63 | * [32B] outpoints hash `hash(tx.inputs.*outpoint)` 64 | * [32B] hash of UTXOs being spent `hash(input_utxos)` 65 | * [8B] `index` 66 | * non-0: 67 | * [1B] constant `0x01` 68 | * [32B] current outpoint `tx.inputs[index].outpoint` 69 | * [32B] hash of UTXO being spent `hash(input_utxos[index])` 70 | * If `sighash & 0x03` is: 71 | * `SIGHASH_ALL`: 72 | * [1B] constant `0x01` 73 | * [32B] hash of all outputs `hash(tx.outputs)` 74 | * `SIGHASH_NONE`: 75 | * [1B] constant `0x02` 76 | * `SIGHASH_SINGLE` 77 | * [1B] constant `0x03` 78 | * If `index` < `tx.outputs.len()`: 79 | * true: 80 | * [32B] hash of output matching current input index `hash(tx.outputs[index])` 81 | * false: 82 | * [32B] constant hash `0x0000...00000` 83 | * [8B] `time_lock` 84 | * [4B] `codesep_pos` 85 | 86 | ## Notes 87 | 88 | The `tx.inputs.*witness` fields are not signed since they cointain the signatures. 89 | 90 | The `tx.inputs.*lock` fields do not show up directly. They are, however, committed to indirectly 91 | because the `lock` field is fully determined by contents of the output being spent by the input 92 | by requiring it to conform to a particular hash (e.g. like in P2SH or requiring it to be empty). 93 | 94 | Many of the hashes included in the resultant message will be the same for many signatures 95 | and can be cached or pre-calculated. 96 | 97 | The message is at most 119 bytes long. 98 | 99 | ## References 100 | 101 | * [SCALE encoding](https://substrate.dev/docs/en/knowledgebase/advanced/codec), 102 | [github](https://github.com/paritytech/parity-scale-codec) 103 | * [SegWit signatures](https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki) 104 | * [Taproot signatures](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#signature-validation-rules) 105 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.2" 2 | 3 | services: 4 | dev: 5 | container_name: node-template 6 | image: paritytech/ci-linux:974ba3ac-20201006 7 | working_dir: /var/www/node-template 8 | ports: 9 | - "9944:9944" 10 | environment: 11 | - CARGO_HOME=/var/www/node-template/.cargo 12 | volumes: 13 | - .:/var/www/node-template 14 | - type: bind 15 | source: ./.local 16 | target: /root/.local 17 | command: bash -c "cargo build --release && ./target/release/node-template --dev --ws-external" 18 | -------------------------------------------------------------------------------- /docs/rewards.md: -------------------------------------------------------------------------------- 1 | # Rewards 2 | 3 | ## Block Rewards 4 | For each block they produce, a validator receives a reward. This section explains how to determine the block reward. 5 | 6 | Since block production is set to occur every minute, approximately 7 | 8 | 1 block/minute * 60 minutes/hour * 24 hours/day * 365 days/year = **525,600 blocks** are created *per year*. 9 | 10 | We define a *block-year* as a sequence of 525,600 consecutive block indices. In this way, the block-year changes approximately every calendar year. 11 | 12 | During the first block-year (i.e. for the first 525,600 blocks created), a fixed amount of 100 MLT tokens per block produced is awarded. 13 | Every block-year thereafter, the reward per block drops by 25%, with a limit of 0.1 MLT tokens per block. 14 | 15 | | Block-year | Reward per block (in MLT tokens) | 16 | | ---------- | -------------------------------- | 17 | | 1 | 100 | 18 | | 2 | 75 | 19 | | 3 | 50 | 20 | | 4 | 25 | 21 | | 5+ | 0.1 | 22 | 23 | 24 | ## Transaction Fees 25 | The transaction fees for UTXO spending and `withdraw_stake` also go to the block author. 26 | The `unlock_request_for_withdrawal` is free. 27 | -------------------------------------------------------------------------------- /docs/staking.md: -------------------------------------------------------------------------------- 1 | # Staking 2 | 3 | Mintlayer borrows from Substrate's [staking system](https://github.com/paritytech/substrate/blob/master/frame/staking/README.md), minus the elections and nominators. 4 | This means being a validator is as simple as locking your utxos: the higher your stake, the higher your chances of being chosen. 5 | 6 | A few terms to recall before we proceed: 7 | - controller account 8 | - stash account 9 | - session key 10 | 11 | Substrate has a documentaton about these [account abstractions](https://docs.substrate.io/v3/concepts/account-abstractions/) to help us understand the reasons behind this design. 12 | 13 | #### Sessions, Era and Bonding Duration 14 | * [*Session*](https://paritytech.github.io/substrate/latest/pallet_session/#terminology) - Substrate defines this as *a period of time (measured in blocks) that has a constant set of validators. Validators can only join or exit the validator set at a session change. A session is measured in block numbers*. 15 | In Mintlayer, a session is currently set to **5 blocks**. 16 | * *Era* - taken from Substrate's staking pallet *as a (whole) number of sessions, which is the period that the validator set is recalculated*. 17 | In Mintlayer, an era has been set to **2 sessions**. 18 | * *Bonding Duration* - Once funds are unlocked, a duration (measured in eras) must pass until the funds can actually be withdrawn. 19 | In Mintlayer, bonding duration is set to **2 eras** 20 | 21 | ### Locking UTXOs for Staking 22 | In substrate's staking system, locking your funds invovlves several steps: 23 | Firstly, bond your controller account to your stash account. 24 | Secondly, [generate your session keys](https://docs.substrate.io/v3/concepts/session-keys/) *and* **set them up in your node**. See [key_management.md](key_management.md) for more details. 25 | Lastly, [apply for the role of validator](https://docs.rs/pallet-staking/3.0.0/pallet_staking/#validating). 26 | You will then be declared a candidate to be a validator for the next era. 27 | 28 | These steps are the same for Mintlayer, but they are compounded into one *spend*: 29 | 1. Generate the session key, just as in Substrate. 30 | 2. In your signed transaction, use the destination **`LockForStaking`** and insert the ``, ``, ``. 31 | 3. Execute the *spend* call. 32 | 33 | **Note**: The *minimum amount* to stake is **40,000 MLT**. 34 | #### Locking Extra UTXOs for Staking 35 | To lock additional funds, follow the same step as above, replacing **`LockForStaking`** with ***`LockExtraForStaking`***. 36 | You do not need to supply your session key again. 37 | 38 | #### Unlocking UTXOs for Withdrawal 39 | Wanting to chill from validating and withdraw your locked utxos? 40 | In Substrate, this involves two steps: *chill* and *unbond*. 41 | Mintlayer makes it possible in one transaction call: **`unlock_request_for_withdrawal`** using the stash account. 42 | Chilling is effective at the beginning of the next era. 43 | However, keep in mind the *bonding duration* (see above): for instance, if the unlocking is successful at 5th era, 44 | then withdrawal becomes possible at the 7th era. 45 | 46 | #### Withdraw UTXOs 47 | Like Unlocking, withdrawal is done in a single call, **`withdraw_stake`**, using the stash account. 48 | This is possible only after *bonding duration* has passed. 49 | -------------------------------------------------------------------------------- /docs/tokens.md: -------------------------------------------------------------------------------- 1 | # Mintlayer Tokens 2 | **TODO Do we want Rust code in this doc?** 3 | 4 | Each transaction output must carry a data field. This field describes the purpose of the transaction. 5 | 6 | We must highlight the following at the moment: 7 | 8 | - Transfer Tokens or NFT 9 | - Token Issuance 10 | - Burning tokens 11 | - NFT creation 12 | 13 | All transactions must be signed on the client side. This means we cannot sign transactions on the node side. 14 | **TODO what is the connection between these two sentences?** 15 | In the future, there will be changes to the structures of transactions and we will be required to track them. 16 | **TODO by structures above to we mean rust structs? Why is this interesting to the user?** 17 | 18 | ## Transfer Tokens 19 | 20 | **TODO sentence fragment, I don't understand...** 21 | **TODO When do we NOT use the TxData field?** 22 | 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. 23 | 24 | ```rust 25 | TxData { 26 | TokenTransferV1 { 27 | token_id: TokenID, 28 | amount: Value, 29 | } 30 | } 31 | ``` 32 | 33 | ## Issue Tokens 34 | 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?** 35 | **TODO explain remaining fields** 36 | 37 | **TODO understand the comment** 38 | ```rust 39 | TxData { 40 | TokenIssuanceV1 { 41 | token_id: TokenID, 42 | token_ticker: Vec, 43 | amount_to_issue: Value, 44 | // Should be not more than 18 numbers 45 | number_of_decimals: u8, 46 | metadata_URI: Vec, 47 | } 48 | } 49 | ``` 50 | 51 | ### Burn Tokens 52 | **TODO verify - the input should be a utxo that contains tokens, the output should contain the TokenBurn arm** 53 | 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. 54 | 55 | ```rust 56 | TxData { 57 | TokenBurnV1{ 58 | token_id: TokenID, 59 | amount_to_burn: Value, 60 | } 61 | } 62 | ``` 63 | ### NFT 64 | TO DO 65 | 66 | ## Wallet 67 | 68 | TO DO 69 | ## Issue and Transfer Tokens 70 | 71 | **TODO who are these examples meant for?** 72 | ```rust 73 | /* Transfer and Issuance in one Tx */ 74 | 75 | // Alice issues 1_000_000_000 MLS-01, and send them to Karl 76 | let (utxo0, input0) = tx_input_gen_no_signature(); 77 | let tx = Transaction { 78 | inputs: vec![input0], 79 | outputs: vec![ 80 | TransactionOutput::new_pubkey( 81 | ALICE_GENESIS_BALANCE - crate::tokens::Mlt(1000).to_munit(), 82 | H256::from(alice_pub_key), 83 | ), 84 | TransactionOutput::new_p2pk_with_data( 85 | crate::tokens::Mlt(1000).to_munit(), 86 | H256::from(karl_pub_key), 87 | OutputData::TokenIssuanceV1 { 88 | token_ticker: "BensT".as_bytes().to_vec(), 89 | amount_to_issue: 1_000_000_000, 90 | number_of_decimals: 2, 91 | metadata_uri: "mintlayer.org".as_bytes().to_vec(), 92 | }, 93 | ), 94 | ], 95 | time_lock: Default::default(), 96 | } 97 | .sign_unchecked(&[utxo0.clone()], 0, &alice_pub_key); 98 | 99 | let first_issuance_token_id = TokenId::new(&tx.inputs[0]); 100 | assert_ok!(Utxo::spend(Origin::signed(H256::zero()), tx.clone())); 101 | let token_utxo_hash = tx.outpoint(1); 102 | let token_utxo = tx.outputs[1].clone(); 103 | 104 | 105 | // Let's send 300_000_000 and rest back and create another token 106 | let tx = Transaction { 107 | inputs: vec![TransactionInput::new_empty(token_utxo_hash)], 108 | outputs: vec![ 109 | TransactionOutput::new_p2pk_with_data( 110 | 0, 111 | H256::from(alice_pub_key), 112 | OutputData::TokenTransferV1 { 113 | token_id: first_issuance_token_id.clone(), 114 | amount: 300_000_000, 115 | }, 116 | ), 117 | TransactionOutput::new_p2pk_with_data( 118 | 0, 119 | H256::from(karl_pub_key), 120 | OutputData::TokenTransferV1 { 121 | token_id: first_issuance_token_id.clone(), 122 | amount: 700_000_000, 123 | }, 124 | ), 125 | TransactionOutput::new_p2pk_with_data( 126 | 0, 127 | H256::from(karl_pub_key), 128 | OutputData::TokenIssuanceV1 { 129 | token_ticker: "Token".as_bytes().to_vec(), 130 | amount_to_issue: 5_000_000_000, 131 | // Should be not more than 18 numbers 132 | number_of_decimals: 12, 133 | metadata_uri: "mintlayer.org".as_bytes().to_vec(), 134 | }, 135 | ), 136 | ], 137 | time_lock: Default::default(), 138 | } 139 | .sign_unchecked(&[token_utxo.clone()], 0, &karl_pub_key); 140 | assert_ok!(Utxo::spend(Origin::signed(H256::zero()), tx.clone())); 141 | let alice_transfer_utxo_hash = tx.outpoint(0); 142 | let karl_transfer_utxo_hash = tx.outpoint(1); 143 | let karl_issuance_utxo_hash = tx.outpoint(2); 144 | assert!(!UtxoStore::::contains_key(H256::from( 145 | token_utxo_hash 146 | ))); 147 | assert!(UtxoStore::::contains_key(alice_transfer_utxo_hash)); 148 | assert!(UtxoStore::::contains_key(karl_transfer_utxo_hash)); 149 | assert!(UtxoStore::::contains_key(karl_issuance_utxo_hash)); 150 | 151 | 152 | 153 | // Let's check token transfer 154 | UtxoStore::::get(alice_transfer_utxo_hash) 155 | .unwrap() 156 | .data 157 | .map(|x| match x { 158 | OutputData::TokenTransferV1 { token_id, amount } => { 159 | assert_eq!(token_id, first_issuance_token_id); 160 | assert_eq!(amount, 300_000_000); 161 | } 162 | _ => { 163 | panic!("corrupted data"); 164 | } 165 | }) 166 | .unwrap(); 167 | 168 | 169 | 170 | UtxoStore::::get(karl_transfer_utxo_hash) 171 | .unwrap() 172 | .data 173 | .map(|x| match x { 174 | OutputData::TokenTransferV1 { token_id, amount } => { 175 | assert_eq!(token_id, first_issuance_token_id); 176 | assert_eq!(amount, 700_000_000); 177 | } 178 | _ => { 179 | panic!("corrupted data"); 180 | } 181 | }) 182 | .unwrap(); 183 | 184 | 185 | 186 | // Let's check token issuance 187 | UtxoStore::::get(karl_issuance_utxo_hash) 188 | .unwrap() 189 | .data 190 | .map(|x| match x { 191 | OutputData::TokenIssuanceV1 { 192 | token_ticker, 193 | amount_to_issue, 194 | number_of_decimals, 195 | metadata_uri, 196 | } => { 197 | assert_eq!(token_ticker, "Token".as_bytes().to_vec()); 198 | assert_eq!(amount_to_issue, 5_000_000_000); 199 | assert_eq!(number_of_decimals, 12); 200 | assert_eq!(metadata_uri, "mintlayer.org".as_bytes().to_vec()); 201 | } 202 | _ => { 203 | panic!("corrupted data"); 204 | } 205 | }) 206 | .unwrap(); 207 | 208 | ``` 209 | -------------------------------------------------------------------------------- /docs/transaction.md: -------------------------------------------------------------------------------- 1 | # Transactions in Mintlayer 2 | 3 | ## UTXO overview 4 | 5 | **TODO maybe system/model instead of structure?** 6 | Mintlayer uses the Bitcoin UTXO structure instead of the account-based models of Ethereum, Ripple, Stellar, and others. 7 | **TODO need explanation of this sentence, it is not clear to me** 8 | Since each transaction's output is stored separately (even when sent to a single address), it is only possible to spend the entire transaction’s output. 9 | 10 | There are three essential reasons for choosing the UTXO model: 11 | 12 | - It is compatible with technologies already implemented in Bitcoin, such atomic swaps and the Lightning Network. 13 | 14 | **TODO - why does this improve privacy?** 15 | - It is more privacy-oriented: a single wallet usually utilizes multiple addresses, making it difficult and sometimes impossible to determine which addresses belong to whichs user. 16 | 17 | - Payments can be batched together (aggregated) in a single transaction, saving a considerable amount of the space otherwise required for making a single transaction per payment. 18 | 19 | ## How to send a transaction in Mintlayer node 20 | There are three destination types for transaction outputs : 21 | - Pubkey (Currently, only Schnorr public keys are supported) 22 | - LockForStaking 23 | - LockExtraForStaking 24 | 25 | A general Mintlayer transaction looks something like this: 26 | 27 | **TODO Not sure we want this in Rust code. Too developer specific. Not clear what H256 is, witness, lock** 28 | **TODO possibly add a link to information about the utxo system** 29 | **TODO if we go for the rust struct, then we need the data field. Also, what is this field?** 30 | **TODO timelock is not a string..."** 31 | ```rust 32 | Transaction { 33 | inputs: [ 34 | TransactionInput { 35 | outpoint: , 36 | witness: , 37 | lock: [] 38 | }, 39 | ], 40 | 41 | outputs: [ 42 | TransactionOutput { 43 | destination: Destination::Pubkey( 44 | 0xd43593c715fdd31c61141abd04a99fd6 45 | ), 46 | value: 234, 47 | }, 48 | TransactionOutput { 49 | destination: Destination::LockforStaking( 50 | dest: 0x2a29ab9f4878436d45299a061565714c 51 | ), 52 | value: 1000, 53 | }, 54 | ], 55 | 56 | timelock: "" 57 | } 58 | ``` 59 | 60 | **TODO what is the default sighash?** 61 | In Mintlayer, as Substrate, transanctions need to be signed before being submitted to network. Only the default sighash supported for now, so signature data contains: 62 | 63 | - The signature hash method 64 | - The hash of the inputs 65 | - The hash of the outputs 66 | - The timelock 67 | 68 | **TODO Explain what we are showing here** 69 | **TODO We need to document the python mintlayer crate** 70 | **TODO what is utxos[0][0]? Utxos is a two-dimentsional array?** 71 | **TODO I want to see the Transaction python class. What is the utxo[0][1] in the signature?** 72 | **In the second transaction's signature, outpoints instead of outputs** 73 | ### Python 74 | 75 | ```python 76 | from substrateinterface import Keypair 77 | import mintlayer.utxo as utxo 78 | 79 | client = self.nodes[0].rpc_client 80 | 81 | alice = Keypair.create_from_uri('//Alice') 82 | bob = Keypair.create_from_uri('//Bob') 83 | 84 | # fetch the genesis utxo from storage 85 | utxos = list(client.utxos_for(alice)) 86 | 87 | tx1 = utxo.Transaction( 88 | client, 89 | inputs=[ 90 | utxo.Input(utxos[0][0]), 91 | ], 92 | outputs=[ 93 | utxo.Output( 94 | value=50, 95 | destination=utxo.DestPubkey(bob.public_key), 96 | data=None 97 | ), 98 | ]).sign(alice, [utxos[0][1]]) 99 | 100 | client.submit(alice, tx1) 101 | 102 | tx2 = utxo.Transaction( 103 | client, 104 | inputs=[ 105 | utxo.Input(tx1.outpoint(0)), 106 | ], 107 | outputs=[ 108 | utxo.Output( 109 | value=30, 110 | destination=utxo.DestPubkey(alice.public_key), 111 | data=None), 112 | utxo.Output( 113 | value=20, 114 | destination=utxo.DestPubkey(bob.public_key), 115 | data=None), 116 | ]).sign(bob, tx1.outputs) 117 | 118 | client.submit(bob, tx2) 119 | 120 | ``` 121 | 122 | ### polkadot.js 123 | 124 | - Connect to the proper node 125 | - Use Accounts menue 126 | - Transfer 127 | - [TODO] Bad Signature Error 128 | -------------------------------------------------------------------------------- /docs/windows_installation.md: -------------------------------------------------------------------------------- 1 | # Windows Installation 2 | 3 | It is _highly_ recommended to 4 | use [Windows Subsystem Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10) (WSL) 5 | and follow the instructions for [Ubuntu/Debian](README.md#####ubuntudebian). 6 | 7 | Alternatively, some users prefer using virtualization software such as [VirtualBox](https://www.oracle.com/virtualization/technologies/vm/downloads/virtualbox-downloads.html). 8 | 9 | If you do decide to try and use a Windows computer to _natively_ build Mintlayer, do the following: 10 | 11 | 1. Download and install "Build Tools for Visual Studio:" 12 | 13 | - You can get it at this link: https://aka.ms/buildtools. 14 | - Run the installation file: `vs_buildtools.exe`. 15 | - Ensure the "Windows 10 SDK" component is included when installing the Visual C++ Build Tools. 16 | - Restart your computer. 17 | 18 | 2. Install Rust: 19 | 20 | - Detailed instructions are provided by the 21 | [Rust Book](https://doc.rust-lang.org/book/ch01-01-installation.html#installing-rustup-on-windows) 22 | and a quick reference is available at . 23 | 24 | - Download from: https://www.rust-lang.org/tools/install. 25 | - Run the installation file: `rustup-init.exe` for 32 or 64 bis as appropriate. 26 | - It shouldn't prompt you to install \`vs_buildtools\` since you did it in step 1. 27 | - Choose "Default Installation." 28 | - To get started, you need Cargo's bin directory (`%USERPROFILE%\.cargo\bin`) in your PATH 29 | environment variable. Future applications will automatically have the correct environment, 30 | but you may need to restart your current shell. 31 | 32 | 3. Run these commands in Command Prompt (`CMD`) to set up your Wasm Build Environment: 33 | 34 | ```bash 35 | rustup update nightly 36 | rustup update stable 37 | rustup target add wasm32-unknown-unknown --toolchain nightly 38 | ``` 39 | 40 | 4. Install LLVM: https://releases.llvm.org/download.html 41 | 42 | 5. Install OpenSSL with `vcpkg` using PowerShell: 43 | 44 | ```bash 45 | mkdir C:\Tools 46 | cd C:\Tools 47 | git clone https://github.com/Microsoft/vcpkg.git --depth=1 48 | cd vcpkg 49 | .\bootstrap-vcpkg.bat 50 | .\vcpkg.exe install openssl:x64-windows-static 51 | ``` 52 | 53 | 6. Add OpenSSL to your System Variables using PowerShell: 54 | 55 | ```powershell 56 | $env:OPENSSL_DIR = 'C:\Tools\vcpkg\installed\x64-windows-static' 57 | $env:OPENSSL_STATIC = 'Yes' 58 | [System.Environment]::SetEnvironmentVariable('OPENSSL_DIR', $env:OPENSSL_DIR, [System.EnvironmentVariableTarget]::User) 59 | [System.Environment]::SetEnvironmentVariable('OPENSSL_STATIC', $env:OPENSSL_STATIC, [System.EnvironmentVariableTarget]::User) 60 | ``` 61 | 62 | 7. Install `cmake`: https://cmake.org/download/ 63 | 64 | 8. Install `make` 65 | 66 | - This can be done using Chocolatey. First you need to install the Chocolatey package manager: https://chocolatey.org/install 67 | - Once Chocolatey installed you can install make: 68 | 69 | ``` 70 | choco install make 71 | ``` 72 | >>>>>>> cc31c24034370edf63820450e1b2a50814861dd2 73 | -------------------------------------------------------------------------------- /libs/base58_nostd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "base58_nostd" 3 | version = "0.1.0" 4 | edition = "2018" 5 | authors = ["Anton Sinitsyn "] 6 | description = "Encodes and decodes the Bech32 format" 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies.frame-support] 11 | default-features = false 12 | git = 'https://github.com/paritytech/substrate.git' 13 | version = '4.0.0-dev' 14 | branch = "master" 15 | 16 | [dependencies.sp-std] 17 | default-features = false 18 | git = 'https://github.com/paritytech/substrate.git' 19 | version = '4.0.0-dev' 20 | branch = "master" 21 | 22 | [features] 23 | default = ['std'] 24 | testcontext = [] 25 | std = [ 26 | "sp-std/std", 27 | "frame-support/std", 28 | ] 29 | -------------------------------------------------------------------------------- /libs/bech32/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bech32" 3 | version = "0.8.1" 4 | authors = ["Clark Moody"] 5 | repository = "https://github.com/rust-bitcoin/rust-bech32" 6 | description = "Encodes and decodes the Bech32 format" 7 | readme = "README.md" 8 | keywords = ["base32", "encoding", "bech32"] 9 | categories = ["encoding"] 10 | license = "MIT" 11 | 12 | [dependencies.sp-std] 13 | default-features = false 14 | git = "https://github.com/paritytech/substrate.git" 15 | version = "4.0.0-dev" 16 | branch = "master" 17 | 18 | [dependencies.frame-support] 19 | default-features = false 20 | git = "https://github.com/paritytech/substrate.git" 21 | version = "4.0.0-dev" 22 | branch = "master" 23 | 24 | [features] 25 | default = ['std'] 26 | testcontext = [] 27 | std = [ 28 | "sp-std/std", 29 | "frame-support/std", 30 | ] 31 | -------------------------------------------------------------------------------- /libs/bech32/README.md: -------------------------------------------------------------------------------- 1 | # Bech32 Rust 2 | 3 | Build and test the library with 4 | ``` 5 | $ cargo test 6 | ``` 7 | 8 | Build the documentation with 9 | ``` 10 | $ cargo doc 11 | ``` 12 | 13 | Documentation output is in `./target/doc/bech32/index.html` 14 | -------------------------------------------------------------------------------- /libs/chainscript/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['Lukas Kuklinek '] 3 | description = 'An interpreter for bitcoin script and its dialects' 4 | edition = '2018' 5 | name = 'chainscript' 6 | readme = 'README.md' 7 | version = '0.1.0' 8 | license = 'MIT' 9 | 10 | [package.metadata.docs.rs] 11 | targets = ['x86_64-unknown-linux-gnu'] 12 | 13 | [dependencies] 14 | # external dependencies 15 | sha-1 = { default-features = false, version = "0.9.7" } 16 | ripemd160 = { default-features = false, version = "0.9.1" } 17 | displaydoc = { default-features = false, version = "0.2" } 18 | 19 | # Substrate dependencies 20 | 21 | codec = { default-features = false, features = ['derive'], package = 'parity-scale-codec', version = '2.0.0' } 22 | sp-core = { default-features = false, version = '4.0.0-dev', git = 'https://github.com/paritytech/substrate.git', branch = 'master'} 23 | sp-io = {default-features = false, version = '4.0.0-dev', git = 'https://github.com/paritytech/substrate.git', branch = 'master'} 24 | sp-runtime = {default-features = false, version = '4.0.0-dev', git = 'https://github.com/paritytech/substrate.git', branch = 'master'} 25 | sp-std = { default-features = false, version = '4.0.0-dev', git = 'https://github.com/paritytech/substrate.git', branch = 'master'} 26 | frame-support = { default-features = false, version = '4.0.0-dev', git = 'https://github.com/paritytech/substrate.git', branch = 'master'} 27 | 28 | [dev-dependencies] 29 | # serde = '1.0.119' 30 | hex-literal = "0.3.1" 31 | proptest = "1.0.0" 32 | 33 | [features] 34 | default = ['std', 'testcontext'] 35 | testcontext = [] 36 | std = [ 37 | "codec/std", 38 | "sp-io/std", 39 | "sp-core/std", 40 | "sp-std/std", 41 | "sp-runtime/std", 42 | "frame-support/std", 43 | ] 44 | -------------------------------------------------------------------------------- /libs/chainscript/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 RBB S.r.l 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /libs/chainscript/README.md: -------------------------------------------------------------------------------- 1 | # Chainscript 2 | 3 | A rust library providing an interpreter and a set of tools for working with Bitcoinscript-like 4 | bytecode languages. 5 | 6 | Code that deals with opcodes and script manipulation is originally [based on the `rust-bitcoin` 7 | project](https://github.com/rust-bitcoin/rust-bitcoin/tree/bd5d875e8ac87). That applies to 8 | the following modules: 9 | 10 | * `src/error.rs` 11 | * `src/opcodes.rs` 12 | * `src/script.rs` 13 | * `src/util.rs` 14 | 15 | For more detailed docs, see the [module-level comments](src/lib.rs) in the top-level module 16 | or alternatively run `cargo doc --open`. 17 | -------------------------------------------------------------------------------- /libs/chainscript/src/context.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 RBB S.r.l 2 | // opensource@mintlayer.org 3 | // SPDX-License-Identifier: MIT 4 | // Licensed under the MIT License; 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://spdx.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Author(s): L. Kuklinek 17 | 18 | //! Context provide interface between script engine and blockchain 19 | 20 | /// Result of parsing data with possible future extensions. 21 | #[derive(PartialEq, Eq, Debug)] 22 | pub enum ParseResult { 23 | /// Decoding successful 24 | Ok(T), 25 | /// Decoding failed 26 | Err, 27 | /// Reserved for future extensions 28 | Reserved, 29 | } 30 | 31 | impl From> for ParseResult { 32 | fn from(o: Option) -> Self { 33 | o.map_or(ParseResult::Err, ParseResult::Ok) 34 | } 35 | } 36 | 37 | /// Context for the script interpreter. 38 | /// 39 | /// This trait defines how the interpreter interfaces with the blockchain. It allows the client 40 | /// to adjust the behaviour of the interpreter by having pluggable signature verification routines 41 | /// and by selectively enabling various interpreter features. It is expected that all data the 42 | /// interpreter takes as implicit inputs (such as transaction hashes that the signatures sign, 43 | /// block height for time locks, etc.) are provided by a type that implements Context. 44 | /// 45 | /// ## TODO 46 | /// 47 | /// * This interface is currently rather monolithic. It may be sensible to break it down into 48 | /// multiple smaller ones for greater flexibility in the future. 49 | /// * The interface is not fully finalized. It is likely to change as new requirements come in. E.g. 50 | /// it may be currently too limited to support signature batching. 51 | /// * The constants may be turned into methods to allow chain forks. 52 | pub trait Context { 53 | /// Maximum number of bytes pushable to the stack 54 | const MAX_SCRIPT_ELEMENT_SIZE: usize = 520; 55 | 56 | /// Maximum number of elements on the stack 57 | const MAX_STACK_ELEMENTS: usize = 1000; 58 | 59 | /// Maximum number of public keys per multisig 60 | const MAX_PUBKEYS_PER_MULTISIG: usize; 61 | 62 | /// Maximum script length in bytes 63 | const MAX_SCRIPT_SIZE: usize; 64 | 65 | /// Public key type. 66 | type Public; 67 | 68 | /// Data needed to verify a signature. This probably contains signature, public key, sighash 69 | /// if used and other data used for verification. 70 | type SignatureData; 71 | 72 | /// Extract a pubkey and check it is in the correct format. 73 | fn parse_pubkey(&self, pk: &[u8]) -> ParseResult; 74 | 75 | /// Extract a signature and check it is in the correct format. Pubkey is provided since it may 76 | /// determine signature format and is likely to be included in the result. 77 | fn parse_signature(&self, pk: Self::Public, sig: &[u8]) -> Option; 78 | 79 | /// Verify signature. 80 | fn verify_signature( 81 | &self, 82 | sig: &Self::SignatureData, 83 | subscript: &[u8], 84 | codesep_idx: u32, 85 | ) -> bool; 86 | 87 | /// Check absolute time lock. 88 | fn check_lock_time(&self, _lock_time: i64) -> bool { 89 | true 90 | } 91 | 92 | /// Check relative time lock. 93 | fn check_sequence(&self, _sequence: i64) -> bool { 94 | true 95 | } 96 | 97 | /// Enforce minimal push. 98 | fn enforce_minimal_push(&self) -> bool { 99 | true 100 | } 101 | 102 | /// Force the condition for OP_(NOT)IF to be either `[]` or `[0x01]`, fail script otherwise. 103 | fn enforce_minimal_if(&self) -> bool { 104 | true 105 | } 106 | } 107 | 108 | // A test context implementation. 109 | // Used for testing and as an example of what a Context might look like. 110 | #[cfg(any(test, feature = "testcontext"))] 111 | pub mod testcontext { 112 | 113 | use super::*; 114 | use crate::util::sha256; 115 | use core::convert::TryFrom; 116 | 117 | /// Test context. 118 | /// 119 | /// The Context implementation for testing. The transaction hash (just 4 bytes for tesing) has 120 | /// to be provided explicitly as a byte string. Signature scheme is very simple: The bitwise xor 121 | /// of transaction hash, signature and public key has to be equal to zero. Not recommended for 122 | /// production. 123 | #[derive(Default)] 124 | pub struct TestContext { 125 | pub transaction: Vec, 126 | pub block_height: u64, 127 | } 128 | 129 | impl TestContext { 130 | /// New test context 131 | pub fn new(transaction: Vec) -> Self { 132 | Self { 133 | transaction, 134 | block_height: 0, 135 | } 136 | } 137 | 138 | /// New test context at particular block height 139 | pub fn new_at_height(transaction: Vec, block_height: u64) -> Self { 140 | Self { 141 | transaction, 142 | block_height, 143 | } 144 | } 145 | } 146 | 147 | impl Context for TestContext { 148 | const MAX_PUBKEYS_PER_MULTISIG: usize = 20; 149 | const MAX_SCRIPT_SIZE: usize = 10000; 150 | 151 | // Signatures, keys and transaction IDs are just 4-byte binary data each. 152 | type SignatureData = [u8; 4]; 153 | type Public = [u8; 4]; 154 | 155 | fn parse_signature(&self, pk: Self::Public, sig: &[u8]) -> Option { 156 | let res: Vec<_> = sig.iter().zip(pk.iter()).map(|(&s, &p)| s ^ p).collect(); 157 | Self::SignatureData::try_from(&res[..]).ok() 158 | } 159 | 160 | fn parse_pubkey(&self, pk: &[u8]) -> ParseResult { 161 | Self::Public::try_from(pk).ok().into() 162 | } 163 | 164 | fn verify_signature(&self, sig: &Self::SignatureData, subscript: &[u8], _ix: u32) -> bool { 165 | let msg = sha256(&[&self.transaction[..], subscript].concat()); 166 | sig.iter().zip(msg.iter()).all(|(&s, &m)| (s ^ m) == 0) 167 | } 168 | 169 | fn check_lock_time(&self, lock_time: i64) -> bool { 170 | self.block_height >= lock_time as u64 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /libs/chainscript/src/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 RBB S.r.l 2 | // opensource@mintlayer.org 3 | // SPDX-License-Identifier: MIT 4 | // Licensed under the MIT License; 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://spdx.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Author(s): L. Kuklinek 17 | 18 | //! Listing of all the error states 19 | 20 | use displaydoc::Display; 21 | 22 | /// Ways that a script might fail. Not everything is split up as 23 | /// much as it could be; patches welcome if more detailed errors 24 | /// would help you. 25 | #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy, Display)] 26 | pub enum Error { 27 | /// Something did a non-minimal push 28 | NonMinimalPush, 29 | /// Some opcode expected a parameter, but it was missing or truncated 30 | EarlyEndOfScript, 31 | /// Tried to read an array off the stack as a number when it was more than 4 bytes 32 | NumericOverflow, 33 | /// Illegal instruction executed 34 | IllegalOp, 35 | /// Syntactically incorrect OP_(NOT)IF/OP_ELSE/OP_ENDIF 36 | UnbalancedIfElse, 37 | /// Stack has insufficient number of elements in it 38 | NotEnoughElementsOnStack, 39 | /// Invalid operand to a script operation. 40 | InvalidOperand, 41 | /// OP_*VERIFY failed verification or OP_RETURN was executed. 42 | VerifyFail, 43 | /// Stack not clean after a script run. 44 | StackNotClean, 45 | /// Signature is not in correct format. 46 | SignatureFormat, 47 | /// Pubkey is not in correct format. 48 | PubkeyFormat, 49 | /// Push data too large. 50 | PushSize, 51 | /// Non-push operation present in context where only data push opcodes are allowed. 52 | PushOnly, 53 | /// Maximum stack size exceeded. 54 | StackSize, 55 | /// Maximum script size exceeded. 56 | ScriptSize, 57 | /// Incorrect number of public keys for multisig 58 | PubkeyCount, 59 | /// Incorrect number of signatures for multisig 60 | SigCount, 61 | /// Time lock interval not elapsed yet 62 | TimeLock, 63 | /// Multisig lacks extra 0 dummy. 64 | NullDummy, 65 | } 66 | 67 | #[cfg(feature = "std")] 68 | impl ::std::error::Error for Error {} 69 | 70 | pub type Result = core::result::Result; 71 | -------------------------------------------------------------------------------- /libs/chainscript/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 RBB S.r.l 2 | // opensource@mintlayer.org 3 | // SPDX-License-Identifier: MIT 4 | // Licensed under the MIT License; 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://spdx.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Author(s): L. Kuklinek 17 | 18 | //! This library provides scripting capabilities targeting blockchain applications largely 19 | //! compatible with Bitcoin script. Most opcodes have semantics identical to Bitcoin script, 20 | //! however the library also provides a number of customization points to allow the user to 21 | //! deviate from, extend and customize the capabilities of the scripting engine. Most notably, 22 | //! signatures can be fully customized. For more info, see the [Context] trait. 23 | //! 24 | //! ## Example 25 | //! 26 | //! Here is how to create a simple script and run it using [TestContext]: 27 | //! 28 | //! ``` 29 | //! use chainscript::{Builder, Stack, TestContext, run_script}; 30 | //! use chainscript::opcodes::all as opc; 31 | //! 32 | //! // Build a script that calculates 3 + 5. 33 | //! let script = Builder::new() 34 | //! .push_int(3) 35 | //! .push_int(5) 36 | //! .push_opcode(opc::OP_ADD) 37 | //! .into_script(); 38 | //! 39 | //! // Set up stack and context, run the interpreter. 40 | //! let stack = Stack::default(); 41 | //! let ctx = TestContext::new("TRANSACTION DATA HERE".as_bytes().to_owned()); 42 | //! let result = run_script(&ctx, &script, stack); 43 | //! 44 | //! // Check if the final stack result is [0x08]. 45 | //! let mut expected = Stack::from(vec![vec![0x08].into()]); 46 | //! assert_eq!(result, Ok(expected)); 47 | //! ``` 48 | 49 | #![cfg_attr(not(feature = "std"), no_std)] 50 | 51 | #[macro_use] 52 | mod util; 53 | 54 | pub mod context; 55 | mod error; 56 | mod interpreter; 57 | pub mod opcodes; 58 | pub mod script; 59 | pub mod sighash; 60 | 61 | #[cfg(feature = "testcontext")] 62 | pub use context::testcontext::TestContext; 63 | pub use context::Context; 64 | pub use error::{Error, Result}; 65 | pub use interpreter::{run_pushdata, run_script, verify_witness_lock, Stack}; 66 | pub use script::{Builder, Script}; 67 | -------------------------------------------------------------------------------- /libs/chainscript/src/sighash.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 RBB S.r.l 2 | // opensource@mintlayer.org 3 | // SPDX-License-Identifier: MIT 4 | // Licensed under the MIT License; 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://spdx.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Author(s): L. Kuklinek 17 | 18 | use codec::Encode; 19 | 20 | /// Specifies which parts of the transaction a signature commits to. 21 | /// 22 | /// The values of the flags are the same as in Bitcoin. 23 | #[derive(Eq, PartialEq, Clone, Copy, Encode)] 24 | pub struct SigHash(u8); 25 | 26 | impl SigHash { 27 | const DEFAULT: u8 = 0x00; 28 | const ALL: u8 = 0x01; 29 | const NONE: u8 = 0x02; 30 | const SINGLE: u8 = 0x03; 31 | const ANYONECANPAY: u8 = 0x80; 32 | 33 | const MASK_OUT: u8 = 0x7f; 34 | const MASK_IN: u8 = 0x80; 35 | 36 | pub fn from_u8(sighash_byte: u8) -> Option { 37 | let ok = matches!( 38 | sighash_byte & Self::MASK_OUT, 39 | Self::ALL | Self::NONE | Self::SINGLE 40 | ); 41 | ok.then(|| Self(sighash_byte)) 42 | } 43 | 44 | pub fn input_mode(&self) -> InputMode { 45 | match self.0 & Self::MASK_IN { 46 | Self::ANYONECANPAY => InputMode::AnyoneCanPay, 47 | _ => InputMode::CommitWhoPays, 48 | } 49 | } 50 | 51 | pub fn output_mode(&self) -> OutputMode { 52 | match self.0 & Self::MASK_OUT { 53 | Self::NONE => OutputMode::None, 54 | Self::SINGLE => OutputMode::Single, 55 | _ => OutputMode::All, 56 | } 57 | } 58 | } 59 | 60 | impl Default for SigHash { 61 | fn default() -> Self { 62 | Self(Self::DEFAULT) 63 | } 64 | } 65 | 66 | /// How inputs should be hashed 67 | pub enum InputMode { 68 | /// Commit to all inputs 69 | CommitWhoPays, 70 | /// Commit to the current input only 71 | AnyoneCanPay, 72 | } 73 | 74 | /// How outputs should be hashed 75 | pub enum OutputMode { 76 | /// Commit to all outputs 77 | All, 78 | /// Don't commit to any outputs 79 | None, 80 | /// Commit to the output corresponding to the current input 81 | Single, 82 | } 83 | -------------------------------------------------------------------------------- /libs/chainscript/src/util.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 RBB S.r.l 2 | // opensource@mintlayer.org 3 | // SPDX-License-Identifier: MIT 4 | // Licensed under the MIT License; 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://spdx.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Author(s): L. Kuklinek 17 | 18 | //! Various uncategorised utilities 19 | 20 | /// Implements standard indexing methods for a given wrapper type 21 | macro_rules! impl_index_newtype { 22 | ($thing:ident, $ty:ty) => { 23 | impl ::core::ops::Index for $thing { 24 | type Output = $ty; 25 | 26 | #[inline] 27 | fn index(&self, index: usize) -> &$ty { 28 | &self.0[index] 29 | } 30 | } 31 | 32 | impl ::core::ops::Index<::core::ops::Range> for $thing { 33 | type Output = [$ty]; 34 | 35 | #[inline] 36 | fn index(&self, index: ::core::ops::Range) -> &[$ty] { 37 | &self.0[index] 38 | } 39 | } 40 | 41 | impl ::core::ops::Index<::core::ops::RangeTo> for $thing { 42 | type Output = [$ty]; 43 | 44 | #[inline] 45 | fn index(&self, index: ::core::ops::RangeTo) -> &[$ty] { 46 | &self.0[index] 47 | } 48 | } 49 | 50 | impl ::core::ops::Index<::core::ops::RangeFrom> for $thing { 51 | type Output = [$ty]; 52 | 53 | #[inline] 54 | fn index(&self, index: ::core::ops::RangeFrom) -> &[$ty] { 55 | &self.0[index] 56 | } 57 | } 58 | 59 | impl ::core::ops::Index<::core::ops::RangeFull> for $thing { 60 | type Output = [$ty]; 61 | 62 | #[inline] 63 | fn index(&self, _: ::core::ops::RangeFull) -> &[$ty] { 64 | &self.0[..] 65 | } 66 | } 67 | }; 68 | } 69 | 70 | macro_rules! display_from_debug { 71 | ($thing:ident) => { 72 | impl ::core::fmt::Display for $thing { 73 | fn fmt(&self, f: &mut ::core::fmt::Formatter) -> Result<(), ::core::fmt::Error> { 74 | ::core::fmt::Debug::fmt(self, f) 75 | } 76 | } 77 | }; 78 | } 79 | 80 | #[cfg(test)] 81 | macro_rules! hex_script { 82 | ($s:expr) => { 83 | Script::from(Vec::from(hex!($s))) 84 | }; 85 | } 86 | 87 | // Export some hash functions. 88 | pub use sp_io::hashing::sha2_256 as sha256; 89 | 90 | pub fn sha1(data: &[u8]) -> [u8; 20] { 91 | use sha1::{Digest, Sha1}; 92 | Sha1::digest(data).into() 93 | } 94 | 95 | pub fn ripemd160(data: &[u8]) -> [u8; 20] { 96 | use ripemd160::{Digest, Ripemd160}; 97 | Ripemd160::digest(data).into() 98 | } 99 | 100 | pub fn hash256(data: &[u8]) -> [u8; 32] { 101 | sha256(&sha256(data)) 102 | } 103 | 104 | pub fn hash160(data: &[u8]) -> [u8; 20] { 105 | ripemd160(&sha256(data)) 106 | } 107 | -------------------------------------------------------------------------------- /node/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['RBB S.r.l '] 3 | build = 'build.rs' 4 | description = 'The Mintlayer core node' 5 | edition = '2018' 6 | homepage = 'https://substrate.dev' 7 | license = 'Unlicense' 8 | name = 'mintlayer-core' 9 | repository = 'https://github.com/mintlayer/core' 10 | version = '0.1.0' 11 | 12 | [[bin]] 13 | name = 'mintlayer-core' 14 | 15 | [package.metadata.docs.rs] 16 | targets = ['x86_64-unknown-linux-gnu'] 17 | 18 | [build-dependencies] 19 | substrate-build-script-utils = {version = '3.0.0', git = 'https://github.com/paritytech/substrate.git', branch = "master" } 20 | 21 | [dependencies] 22 | jsonrpc-core = '18.0.0' 23 | structopt = '0.3.8' 24 | node-template-runtime = {version = '3.0.0', path = '../runtime'} 25 | pallet-utxo-rpc = { path = "../pallets/utxo/rpc" } 26 | pallet-utxo-rpc-runtime-api = { path = "../pallets/utxo/rpc/runtime-api" } 27 | log = "0.4.8" 28 | ureq = "2.2.0" 29 | 30 | [dependencies.serde_json] 31 | version = '1.0.45' 32 | default-features = false 33 | features = ['alloc'] 34 | 35 | [dependencies.serde] 36 | version = '1.0.130' 37 | default-features = false 38 | features = ['derive'] 39 | 40 | [dependencies.frame-benchmarking] 41 | git = 'https://github.com/paritytech/substrate.git' 42 | version = '4.0.0-dev' 43 | branch = "master" 44 | 45 | [dependencies.frame-benchmarking-cli] 46 | git = 'https://github.com/paritytech/substrate.git' 47 | version = '4.0.0-dev' 48 | branch = "master" 49 | 50 | [dependencies.pallet-transaction-payment-rpc] 51 | git = 'https://github.com/paritytech/substrate.git' 52 | version = '4.0.0-dev' 53 | branch = "master" 54 | 55 | [dependencies.sc-basic-authorship] 56 | git = 'https://github.com/paritytech/substrate.git' 57 | version = '0.10.0-dev' 58 | branch = "master" 59 | 60 | [dependencies.sc-cli] 61 | features = ['wasmtime'] 62 | git = 'https://github.com/paritytech/substrate.git' 63 | version = '0.10.0-dev' 64 | branch = "master" 65 | 66 | [dependencies.sc-client-api] 67 | git = 'https://github.com/paritytech/substrate.git' 68 | version = '4.0.0-dev' 69 | branch = "master" 70 | 71 | [dependencies.sc-consensus] 72 | git = 'https://github.com/paritytech/substrate.git' 73 | version = '0.10.0-dev' 74 | branch = "master" 75 | 76 | [dependencies.sc-consensus-aura] 77 | git = 'https://github.com/paritytech/substrate.git' 78 | version = '0.10.0-dev' 79 | branch = "master" 80 | 81 | [dependencies.sc-executor] 82 | features = ['wasmtime'] 83 | git = 'https://github.com/paritytech/substrate.git' 84 | version = '0.10.0-dev' 85 | branch = "master" 86 | 87 | [dependencies.sc-finality-grandpa] 88 | git = 'https://github.com/paritytech/substrate.git' 89 | version = '0.10.0-dev' 90 | branch = "master" 91 | 92 | [dependencies.sc-finality-grandpa-rpc] 93 | git = 'https://github.com/paritytech/substrate.git' 94 | version = '0.10.0-dev' 95 | branch = "master" 96 | 97 | [dependencies.sc-network] 98 | git = 'https://github.com/paritytech/substrate.git' 99 | version = "0.10.0-dev" 100 | branch = "master" 101 | 102 | [dependencies.sc-consensus-babe] 103 | git = 'https://github.com/paritytech/substrate.git' 104 | version = "0.10.0-dev" 105 | branch = "master" 106 | 107 | [dependencies.sc-consensus-babe-rpc] 108 | git = 'https://github.com/paritytech/substrate.git' 109 | version = "0.10.0-dev" 110 | branch = "master" 111 | 112 | [dependencies.sc-keystore] 113 | git = 'https://github.com/paritytech/substrate.git' 114 | version = '4.0.0-dev' 115 | branch = "master" 116 | 117 | [dependencies.sc-rpc] 118 | git = 'https://github.com/paritytech/substrate.git' 119 | version = '4.0.0-dev' 120 | branch = "master" 121 | 122 | [dependencies.sc-rpc-api] 123 | git = 'https://github.com/paritytech/substrate.git' 124 | version = '0.10.0-dev' 125 | branch = "master" 126 | 127 | [dependencies.sc-service] 128 | features = ['wasmtime'] 129 | git = 'https://github.com/paritytech/substrate.git' 130 | version = '0.10.0-dev' 131 | branch = "master" 132 | 133 | [dependencies.sc-telemetry] 134 | git = 'https://github.com/paritytech/substrate.git' 135 | version = '4.0.0-dev' 136 | branch = "master" 137 | 138 | [dependencies.sc-transaction-pool] 139 | git = 'https://github.com/paritytech/substrate.git' 140 | version = '4.0.0-dev' 141 | branch = "master" 142 | 143 | [dependencies.sc-transaction-pool-api] 144 | git = 'https://github.com/paritytech/substrate.git' 145 | version = '4.0.0-dev' 146 | branch = "master" 147 | 148 | [dependencies.sp-api] 149 | git = 'https://github.com/paritytech/substrate.git' 150 | version = '4.0.0-dev' 151 | branch = "master" 152 | 153 | [dependencies.sp-block-builder] 154 | git = 'https://github.com/paritytech/substrate.git' 155 | version = '4.0.0-dev' 156 | branch = "master" 157 | 158 | [dependencies.sp-blockchain] 159 | git = 'https://github.com/paritytech/substrate.git' 160 | version = '4.0.0-dev' 161 | branch = "master" 162 | 163 | [dependencies.sp-consensus] 164 | git = 'https://github.com/paritytech/substrate.git' 165 | version = '0.10.0-dev' 166 | branch = "master" 167 | 168 | [dependencies.sp-consensus-aura] 169 | git = 'https://github.com/paritytech/substrate.git' 170 | version = '0.10.0-dev' 171 | branch = "master" 172 | 173 | [dependencies.sp-core] 174 | git = 'https://github.com/paritytech/substrate.git' 175 | version = '4.0.0-dev' 176 | branch = "master" 177 | 178 | [dependencies.sp-finality-grandpa] 179 | git = 'https://github.com/paritytech/substrate.git' 180 | version = '4.0.0-dev' 181 | branch = "master" 182 | 183 | [dependencies.sp-inherents] 184 | git = 'https://github.com/paritytech/substrate.git' 185 | version = '4.0.0-dev' 186 | branch = "master" 187 | 188 | [dependencies.sp-runtime] 189 | git = 'https://github.com/paritytech/substrate.git' 190 | version = '4.0.0-dev' 191 | branch = "master" 192 | 193 | [dependencies.sp-timestamp] 194 | git = 'https://github.com/paritytech/substrate.git' 195 | version = '4.0.0-dev' 196 | branch = "master" 197 | 198 | [dependencies.substrate-frame-rpc-system] 199 | git = 'https://github.com/paritytech/substrate.git' 200 | version = '4.0.0-dev' 201 | branch = "master" 202 | 203 | [dependencies.pallet-contracts] 204 | default-features = false 205 | git = 'https://github.com/paritytech/substrate.git' 206 | version = '4.0.0-dev' 207 | branch = "master" 208 | 209 | [dependencies.pallet-contracts-rpc] 210 | default-features = false 211 | git = 'https://github.com/paritytech/substrate.git' 212 | version = '4.0.0-dev' 213 | branch = "master" 214 | 215 | [dependencies.sp-authorship] 216 | git = 'https://github.com/paritytech/substrate.git' 217 | version = "4.0.0-dev" 218 | branch = "master" 219 | 220 | [dependencies.sc-authority-discovery] 221 | git = 'https://github.com/paritytech/substrate.git' 222 | version = "0.10.0-dev" 223 | branch = "master" 224 | 225 | # local dependencies 226 | # bls_sigs_ref = {version = '0.3.0', path = '../../BLS'} 227 | 228 | [features] 229 | default = [] 230 | runtime-benchmarks = ['node-template-runtime/runtime-benchmarks'] 231 | -------------------------------------------------------------------------------- /node/build.rs: -------------------------------------------------------------------------------- 1 | use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; 2 | 3 | use std::env; 4 | use std::ffi::OsStr; 5 | use std::fs; 6 | use std::path::Path; 7 | 8 | fn write_functional_tests_config_file() { 9 | let cargo_manifest_dir = env!("CARGO_MANIFEST_DIR"); 10 | let profile = env::var("PROFILE").unwrap(); 11 | let bin_name = env::var("CARGO_PKG_NAME").unwrap_or("mintlayer-core".to_owned()); 12 | 13 | let build_dir = Path::new(cargo_manifest_dir).join("..").join("target").join(profile); 14 | let build_dir = build_dir.canonicalize().unwrap_or(build_dir); 15 | 16 | // This doesn't work, so we don't use it until this is fixed 17 | // let exe_path = env::var_os("CARGO_BIN_EXE_mintlayer-core").unwrap(); 18 | // let exe_path = env!("CARGO_BIN_EXE_mintlayer-core"); 19 | // let exe_path = env!("CARGO_BIN_EXE"); 20 | 21 | let exe_path = build_dir.join(bin_name); 22 | let exe_path = exe_path.canonicalize().unwrap_or(exe_path); 23 | 24 | let src_dir = Path::new(&cargo_manifest_dir).join("../"); 25 | let src_dir = src_dir.canonicalize().unwrap_or(src_dir); 26 | let src_dir = src_dir.to_string_lossy().to_string(); 27 | let src_dir = src_dir.as_str(); 28 | 29 | let template_config_file_path = 30 | Path::new(&cargo_manifest_dir).join("../").join("test").join("config.ini.in"); 31 | let template_config_file_content = fs::read_to_string(template_config_file_path).unwrap(); 32 | let template_config_file_content = str::replace( 33 | template_config_file_content.as_str(), 34 | "@abs_top_srcdir@", 35 | src_dir, 36 | ); 37 | let template_config_file_content = str::replace( 38 | template_config_file_content.as_str(), 39 | "@abs_top_builddir@", 40 | build_dir.to_string_lossy().to_string().as_str(), 41 | ); 42 | let template_config_file_content = str::replace( 43 | template_config_file_content.as_str(), 44 | "@EXEEXT@", 45 | exe_path 46 | .extension() 47 | .unwrap_or(OsStr::new("")) 48 | .to_string_lossy() 49 | .to_string() 50 | .as_str(), 51 | ); 52 | 53 | // write the config file 54 | let dest_path = Path::new(&cargo_manifest_dir).join("../").join("test").join("config.ini"); 55 | fs::write(&dest_path, template_config_file_content).unwrap(); 56 | println!("cargo:rerun-if-changed=build.rs"); 57 | println!("cargo:rerun-if-env-changed=PROFILE"); 58 | } 59 | 60 | fn main() { 61 | generate_cargo_keys(); 62 | 63 | rerun_if_git_head_changed(); 64 | 65 | write_functional_tests_config_file(); 66 | } 67 | -------------------------------------------------------------------------------- /node/src/cli.rs: -------------------------------------------------------------------------------- 1 | use sc_cli::RunCmd; 2 | use structopt::StructOpt; 3 | 4 | #[derive(Debug, StructOpt)] 5 | pub struct Cli { 6 | #[structopt(subcommand)] 7 | pub subcommand: Option, 8 | 9 | /// Connect to Mintlayer TestNet 10 | #[structopt(long, conflicts_with_all = &["chain", "dev"])] 11 | pub testnet: bool, 12 | 13 | #[structopt(flatten)] 14 | pub run: RunCmd, 15 | } 16 | 17 | #[derive(Debug, StructOpt)] 18 | pub enum Subcommand { 19 | /// Key management cli utilities 20 | Key(sc_cli::KeySubcommand), 21 | /// Build a chain specification. 22 | BuildSpec(sc_cli::BuildSpecCmd), 23 | 24 | /// Validate blocks. 25 | CheckBlock(sc_cli::CheckBlockCmd), 26 | 27 | /// Export blocks. 28 | ExportBlocks(sc_cli::ExportBlocksCmd), 29 | 30 | /// Export the state of a given block into a chain spec. 31 | ExportState(sc_cli::ExportStateCmd), 32 | 33 | /// Import blocks. 34 | ImportBlocks(sc_cli::ImportBlocksCmd), 35 | 36 | /// Remove the whole chain. 37 | PurgeChain(sc_cli::PurgeChainCmd), 38 | 39 | /// Revert the chain to a previous state. 40 | Revert(sc_cli::RevertCmd), 41 | 42 | /// The custom benchmark subcommmand benchmarking runtime pallets. 43 | #[structopt(name = "benchmark", about = "Benchmark runtime pallets.")] 44 | Benchmark(frame_benchmarking_cli::BenchmarkCmd), 45 | } 46 | -------------------------------------------------------------------------------- /node/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod chain_spec; 2 | pub mod rpc; 3 | pub mod service; 4 | -------------------------------------------------------------------------------- /node/src/main.rs: -------------------------------------------------------------------------------- 1 | //! Substrate Node Template CLI library. 2 | #![warn(missing_docs)] 3 | 4 | mod chain_spec; 5 | #[macro_use] 6 | mod service; 7 | mod cli; 8 | mod command; 9 | mod rpc; 10 | 11 | fn main() -> sc_cli::Result<()> { 12 | command::run() 13 | } 14 | -------------------------------------------------------------------------------- /node/src/rpc.rs: -------------------------------------------------------------------------------- 1 | //! A collection of node-specific RPC methods. 2 | //! Substrate provides the `sc-rpc` crate, which defines the core RPC layer 3 | //! used by Substrate nodes. This file extends those RPC definitions with 4 | //! capabilities that are specific to this project's runtime configuration. 5 | 6 | #![warn(missing_docs)] 7 | 8 | use std::sync::Arc; 9 | 10 | use node_template_runtime::{opaque::Block, AccountId, Balance, BlockNumber, Hash, Index}; 11 | pub use sc_rpc_api::DenyUnsafe; 12 | use sc_transaction_pool_api::TransactionPool; 13 | use sp_api::ProvideRuntimeApi; 14 | use sp_block_builder::BlockBuilder; 15 | use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; 16 | 17 | /// Full client dependencies. 18 | pub struct FullDeps { 19 | /// The client instance to use. 20 | pub client: Arc, 21 | /// Transaction pool instance. 22 | pub pool: Arc

, 23 | /// Whether to deny unsafe calls 24 | pub deny_unsafe: DenyUnsafe, 25 | } 26 | 27 | /// Instantiate all full RPC extensions. 28 | pub fn create_full(deps: FullDeps) -> jsonrpc_core::IoHandler 29 | where 30 | C: ProvideRuntimeApi, 31 | C: HeaderBackend + HeaderMetadata + 'static, 32 | C: Send + Sync + 'static, 33 | C::Api: substrate_frame_rpc_system::AccountNonceApi, 34 | C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, 35 | C::Api: pallet_utxo_rpc::UtxoRuntimeApi, 36 | C::Api: pallet_contracts_rpc::ContractsRuntimeApi, 37 | C::Api: BlockBuilder, 38 | P: TransactionPool + 'static, 39 | { 40 | use pallet_contracts_rpc::{Contracts, ContractsApi}; 41 | use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; 42 | use pallet_utxo_rpc::{Utxo, UtxoApi}; 43 | use substrate_frame_rpc_system::{FullSystem, SystemApi}; 44 | 45 | let mut io = jsonrpc_core::IoHandler::default(); 46 | let FullDeps { 47 | client, 48 | pool, 49 | deny_unsafe, 50 | } = deps; 51 | 52 | io.extend_with(SystemApi::to_delegate(FullSystem::new( 53 | client.clone(), 54 | pool, 55 | deny_unsafe, 56 | ))); 57 | 58 | io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new( 59 | client.clone(), 60 | ))); 61 | 62 | io.extend_with(UtxoApi::to_delegate(Utxo::new(client.clone()))); 63 | io.extend_with(ContractsApi::to_delegate(Contracts::new(client.clone()))); 64 | 65 | // Extend this RPC with a custom API by using the following syntax. 66 | // `YourRpcStruct` should have a reference to a client, which is needed 67 | // to call into the runtime. 68 | // `io.extend_with(YourRpcTrait::to_delegate(YourRpcStruct::new(ReferenceToClient, ...)));` 69 | 70 | io 71 | } 72 | -------------------------------------------------------------------------------- /pallets/pp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["RBB Lab"] 3 | description = 'Programmable pools pallet' 4 | edition = '2018' 5 | license = 'MIT' 6 | name = 'pallet-pp' 7 | readme = 'README.md' 8 | version = '3.0.0' 9 | 10 | [package.metadata.docs.rs] 11 | targets = ['x86_64-unknown-linux-gnu'] 12 | 13 | [dependencies] 14 | log = "0.4.8" 15 | 16 | [dependencies.codec] 17 | default-features = false 18 | features = ['derive'] 19 | package = 'parity-scale-codec' 20 | version = '2.0.0' 21 | 22 | [dependencies.pp-api] 23 | default-features = false 24 | path = "../../traits/pp-api/" 25 | 26 | [dependencies.utxo-api] 27 | default-features = false 28 | path = "../../traits/utxo-api/" 29 | 30 | [dependencies.frame-benchmarking] 31 | default-features = false 32 | git = 'https://github.com/paritytech/substrate.git' 33 | optional = true 34 | version = '4.0.0-dev' 35 | branch = "master" 36 | 37 | [dependencies.frame-support] 38 | default-features = false 39 | git = 'https://github.com/paritytech/substrate.git' 40 | version = '4.0.0-dev' 41 | branch = "master" 42 | 43 | [dependencies.frame-system] 44 | default-features = false 45 | git = 'https://github.com/paritytech/substrate.git' 46 | version = '4.0.0-dev' 47 | branch = "master" 48 | 49 | [dependencies.pallet-contracts] 50 | default-features = false 51 | git = 'https://github.com/paritytech/substrate.git' 52 | version = '4.0.0-dev' 53 | branch = "master" 54 | 55 | [dependencies.pallet-balances] 56 | default-features = false 57 | git = 'https://github.com/paritytech/substrate.git' 58 | version = '4.0.0-dev' 59 | branch = "master" 60 | 61 | [dependencies.pallet-contracts-primitives] 62 | default-features = false 63 | git = 'https://github.com/paritytech/substrate.git' 64 | version = '4.0.0-dev' 65 | branch = "master" 66 | 67 | [dependencies.sp-core] 68 | default-features = false 69 | git = 'https://github.com/paritytech/substrate.git' 70 | version = '4.0.0-dev' 71 | branch = "master" 72 | 73 | [dev-dependencies.serde] 74 | version = '1.0.126' 75 | 76 | [dev-dependencies.sp-io] 77 | default-features = false 78 | git = 'https://github.com/paritytech/substrate.git' 79 | version = '4.0.0-dev' 80 | branch = "master" 81 | 82 | [dev-dependencies.sp-runtime] 83 | default-features = false 84 | git = 'https://github.com/paritytech/substrate.git' 85 | version = '4.0.0-dev' 86 | branch = "master" 87 | 88 | [dev-dependencies.sp-core] 89 | default-features = false 90 | git = 'https://github.com/paritytech/substrate.git' 91 | version = '4.0.0-dev' 92 | branch = "master" 93 | 94 | [features] 95 | default = ['std'] 96 | runtime-benchmarks = ['frame-benchmarking'] 97 | std = [ 98 | 'codec/std', 99 | 'frame-support/std', 100 | 'frame-system/std', 101 | 'frame-benchmarking/std', 102 | 'pallet-contracts/std', 103 | 'pallet-contracts-primitives/std', 104 | ] 105 | try-runtime = ['frame-support/try-runtime'] 106 | -------------------------------------------------------------------------------- /pallets/pp/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 RBB S.r.l 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pallets/pp/README.md: -------------------------------------------------------------------------------- 1 | License: MIT -------------------------------------------------------------------------------- /pallets/pp/src/benchmarking.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 RBB S.r.l 2 | // opensource@mintlayer.org 3 | // SPDX-License-Identifier: MIT 4 | // Licensed under the MIT License; 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://spdx.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Author(s): A. Altonen 17 | //! Benchmarking setup for pallet-pp 18 | 19 | use super::*; 20 | 21 | #[allow(unused)] 22 | use crate::Pallet as PP; 23 | use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; 24 | use frame_system::RawOrigin; 25 | 26 | benchmarks! { 27 | do_something { 28 | let s in 0 .. 100; 29 | let caller: T::AccountId = whitelisted_caller(); 30 | }: _(RawOrigin::Signed(caller), s) 31 | verify { 32 | assert_eq!(Something::::get(), Some(s)); 33 | } 34 | } 35 | 36 | impl_benchmark_test_suite!(PP, crate::mock::new_test_ext(), crate::mock::Test,); 37 | -------------------------------------------------------------------------------- /pallets/pp/src/mock.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 RBB S.r.l 2 | // opensource@mintlayer.org 3 | // SPDX-License-Identifier: MIT 4 | // Licensed under the MIT License; 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://spdx.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Author(s): A. Altonen 17 | // use crate as pallet_pp; 18 | // use sp_core::H256; 19 | // use frame_support::parameter_types; 20 | // use sp_runtime::{ 21 | // traits::{BlakeTwo256, IdentityLookup}, testing::Header, 22 | // }; 23 | // use frame_system as system; 24 | 25 | // type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 26 | // type Block = frame_system::mocking::MockBlock; 27 | 28 | // // Configure a mock runtime to test the pallet. 29 | // frame_support::construct_runtime!( 30 | // pub enum Test where 31 | // Block = Block, 32 | // NodeBlock = Block, 33 | // UncheckedExtrinsic = UncheckedExtrinsic, 34 | // { 35 | // System: frame_system::{Pallet, Call, Config, Storage, Event}, 36 | // PpModule: pallet_pp::{Pallet, Call, Storage, Event}, 37 | // } 38 | // ); 39 | 40 | // parameter_types! { 41 | // pub const BlockHashCount: u64 = 250; 42 | // pub const SS58Prefix: u8 = 42; 43 | // } 44 | 45 | // impl system::Config for Test { 46 | // type BaseCallFilter = frame_support::traits::AllowAll; 47 | // type BlockWeights = (); 48 | // type BlockLength = (); 49 | // type DbWeight = (); 50 | // type Origin = Origin; 51 | // type Call = Call; 52 | // type Index = u64; 53 | // type BlockNumber = u64; 54 | // type Hash = H256; 55 | // type Hashing = BlakeTwo256; 56 | // type AccountId = u64; 57 | // type Lookup = IdentityLookup; 58 | // type Header = Header; 59 | // type Event = Event; 60 | // type BlockHashCount = BlockHashCount; 61 | // type Version = (); 62 | // type PalletInfo = PalletInfo; 63 | // type AccountData = (); 64 | // type OnNewAccount = (); 65 | // type OnKilledAccount = (); 66 | // type SystemWeightInfo = (); 67 | // type SS58Prefix = SS58Prefix; 68 | // type OnSetCode = (); 69 | // } 70 | 71 | // impl pallet_pp::Config for Test { 72 | // type Event = Event; 73 | // } 74 | 75 | // parameter_types! { 76 | // pub TombstoneDeposit: Balance = deposit( 77 | // 1, 78 | // >::contract_info_size() 79 | // ); 80 | // pub DepositPerContract: Balance = TombstoneDeposit::get(); 81 | // pub const DepositPerStorageByte: Balance = deposit(0, 1); 82 | // pub const DepositPerStorageItem: Balance = deposit(1, 0); 83 | // pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * DAYS); 84 | // pub const SurchargeReward: Balance = 150 * MILLICENTS; 85 | // pub const SignedClaimHandicap: u32 = 2; 86 | // pub const MaxValueSize: u32 = 16 * 1024; 87 | 88 | // // The lazy deletion runs inside on_initialize. 89 | // pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO * 90 | // BlockWeights::get().max_block; 91 | 92 | // // The weight needed for decoding the queue should be less or equal than a fifth 93 | // // of the overall weight dedicated to the lazy deletion. 94 | // pub DeletionQueueDepth: u32 = ((DeletionWeightLimit::get() / ( 95 | // ::WeightInfo::on_initialize_per_queue_item(1) - 96 | // ::WeightInfo::on_initialize_per_queue_item(0) 97 | // )) / 5) as u32; 98 | 99 | // pub Schedule: pallet_contracts::Schedule = Default::default(); 100 | // } 101 | 102 | // impl pallet_contracts::Config for Runtime { 103 | // type Time = Timestamp; 104 | // type Randomness = RandomnessCollectiveFlip; 105 | // type Currency = Balances; 106 | // type Event = Event; 107 | // type RentPayment = (); 108 | // type SignedClaimHandicap = SignedClaimHandicap; 109 | // type TombstoneDeposit = TombstoneDeposit; 110 | // type DepositPerContract = DepositPerContract; 111 | // type DepositPerStorageByte = DepositPerStorageByte; 112 | // type DepositPerStorageItem = DepositPerStorageItem; 113 | // type RentFraction = RentFraction; 114 | // type SurchargeReward = SurchargeReward; 115 | // type WeightPrice = pallet_transaction_payment::Pallet; 116 | // type WeightInfo = pallet_contracts::weights::SubstrateWeight; 117 | // type ChainExtension = (); 118 | // type DeletionQueueDepth = DeletionQueueDepth; 119 | // type DeletionWeightLimit = DeletionWeightLimit; 120 | // type Call = Call; 121 | // /// The safest default is to allow no calls at all. 122 | // /// 123 | // /// Runtimes should whitelist dispatchables that are allowed to be called from contracts 124 | // /// and make sure they are stable. Dispatchables exposed to contracts are not allowed to 125 | // /// change because that would break already deployed contracts. The `Call` structure itself 126 | // /// is not allowed to change the indices of existing pallets, too. 127 | // type CallFilter = DenyAll; 128 | // type Schedule = Schedule; 129 | // type CallStack = [pallet_contracts::Frame; 31]; 130 | // } 131 | 132 | // // Build genesis storage according to the mock runtime. 133 | // pub fn new_test_ext() -> sp_io::TestExternalities { 134 | // system::GenesisConfig::default().build_storage::().unwrap().into() 135 | // } 136 | -------------------------------------------------------------------------------- /pallets/pp/src/tests.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 RBB S.r.l 2 | // opensource@mintlayer.org 3 | // SPDX-License-Identifier: MIT 4 | // Licensed under the MIT License; 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://spdx.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Author(s): A. Altonen 17 | // use crate::{Error, mock::*}; 18 | // use frame_support::{assert_ok, assert_noop}; 19 | 20 | // #[test] 21 | // fn it_works_for_default_value() { 22 | // new_test_ext().execute_with(|| { 23 | // // Dispatch a signed extrinsic. 24 | // assert_ok!(PpModule::do_something(Origin::signed(1), 42)); 25 | // // Read pallet storage and assert an expected result. 26 | // assert_eq!(PpModule::something(), Some(42)); 27 | // }); 28 | // } 29 | 30 | // #[test] 31 | // fn correct_error_for_none_value() { 32 | // new_test_ext().execute_with(|| { 33 | // // Ensure the expected error is thrown when no value is present. 34 | // assert_noop!( 35 | // PpModule::cause_error(Origin::signed(1)), 36 | // Error::::NoneValue 37 | // ); 38 | // }); 39 | // } 40 | -------------------------------------------------------------------------------- /pallets/template/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ['Substrate DevHub '] 3 | description = 'FRAME pallet template for defining custom runtime logic.' 4 | edition = '2018' 5 | homepage = 'https://substrate.dev' 6 | license = 'Unlicense' 7 | name = 'pallet-template' 8 | readme = 'README.md' 9 | repository = 'https://github.com/substrate-developer-hub/substrate-node-template/' 10 | version = '3.0.0' 11 | 12 | [package.metadata.docs.rs] 13 | targets = ['x86_64-unknown-linux-gnu'] 14 | 15 | [dependencies.codec] 16 | default-features = false 17 | features = ['derive'] 18 | package = 'parity-scale-codec' 19 | version = '2.0.0' 20 | 21 | [dependencies.frame-support] 22 | default-features = false 23 | git = 'https://github.com/paritytech/substrate.git' 24 | version = '4.0.0-dev' 25 | branch = "master" 26 | 27 | [dependencies.frame-system] 28 | default-features = false 29 | git = 'https://github.com/paritytech/substrate.git' 30 | version = '4.0.0-dev' 31 | branch = "master" 32 | 33 | [dependencies.frame-benchmarking] 34 | default-features = false 35 | git = 'https://github.com/paritytech/substrate.git' 36 | optional = true 37 | version = '4.0.0-dev' 38 | branch = "master" 39 | 40 | [dev-dependencies.serde] 41 | version = '1.0.126' 42 | 43 | [dev-dependencies.sp-runtime] 44 | default-features = false 45 | git = 'https://github.com/paritytech/substrate.git' 46 | version = '4.0.0-dev' 47 | branch = "master" 48 | 49 | [dev-dependencies.sp-core] 50 | default-features = false 51 | git = 'https://github.com/paritytech/substrate.git' 52 | version = '4.0.0-dev' 53 | branch = "master" 54 | 55 | [dev-dependencies.sp-io] 56 | default-features = false 57 | git = 'https://github.com/paritytech/substrate.git' 58 | version = '4.0.0-dev' 59 | branch = "master" 60 | 61 | [features] 62 | default = ['std'] 63 | runtime-benchmarks = ['frame-benchmarking'] 64 | std = [ 65 | 'codec/std', 66 | 'frame-support/std', 67 | 'frame-system/std', 68 | 'frame-benchmarking/std', 69 | ] 70 | try-runtime = ['frame-support/try-runtime'] 71 | -------------------------------------------------------------------------------- /pallets/template/README.md: -------------------------------------------------------------------------------- 1 | License: Unlicense -------------------------------------------------------------------------------- /pallets/template/src/benchmarking.rs: -------------------------------------------------------------------------------- 1 | //! Benchmarking setup for pallet-template 2 | 3 | use super::*; 4 | 5 | #[allow(unused)] 6 | use crate::Pallet as Template; 7 | use frame_benchmarking::{benchmarks, impl_benchmark_test_suite, whitelisted_caller}; 8 | use frame_system::RawOrigin; 9 | 10 | benchmarks! { 11 | do_something { 12 | let s in 0 .. 100; 13 | let caller: T::AccountId = whitelisted_caller(); 14 | }: _(RawOrigin::Signed(caller), s) 15 | verify { 16 | assert_eq!(Something::::get(), Some(s)); 17 | } 18 | } 19 | 20 | impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test,); 21 | -------------------------------------------------------------------------------- /pallets/template/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | /// Edit this file to define custom logic or remove it if it is not needed. 4 | /// Learn more about FRAME and the core library of Substrate FRAME pallets: 5 | /// 6 | pub use pallet::*; 7 | 8 | #[cfg(test)] 9 | mod mock; 10 | 11 | #[cfg(test)] 12 | mod tests; 13 | 14 | #[cfg(feature = "runtime-benchmarks")] 15 | mod benchmarking; 16 | 17 | #[frame_support::pallet] 18 | pub mod pallet { 19 | use frame_support::{dispatch::DispatchResult, pallet_prelude::*}; 20 | use frame_system::pallet_prelude::*; 21 | 22 | /// Configure the pallet by specifying the parameters and types on which it depends. 23 | #[pallet::config] 24 | pub trait Config: frame_system::Config { 25 | /// Because this pallet emits events, it depends on the runtime's definition of an event. 26 | type Event: From> + IsType<::Event>; 27 | } 28 | 29 | #[pallet::pallet] 30 | #[pallet::generate_store(pub(super) trait Store)] 31 | pub struct Pallet(_); 32 | 33 | // The pallet's runtime storage items. 34 | // https://substrate.dev/docs/en/knowledgebase/runtime/storage 35 | #[pallet::storage] 36 | #[pallet::getter(fn something)] 37 | // Learn more about declaring storage items: 38 | // https://substrate.dev/docs/en/knowledgebase/runtime/storage#declaring-storage-items 39 | pub type Something = StorageValue<_, u32>; 40 | 41 | // Pallets use events to inform users when important changes are made. 42 | // https://substrate.dev/docs/en/knowledgebase/runtime/events 43 | #[pallet::event] 44 | #[pallet::metadata(T::AccountId = "AccountId")] 45 | #[pallet::generate_deposit(pub(super) fn deposit_event)] 46 | pub enum Event { 47 | /// Event documentation should end with an array that provides descriptive names for event 48 | /// parameters. [something, who] 49 | SomethingStored(u32, T::AccountId), 50 | } 51 | 52 | // Errors inform users that something went wrong. 53 | #[pallet::error] 54 | pub enum Error { 55 | /// Error names should be descriptive. 56 | NoneValue, 57 | /// Errors should have helpful documentation associated with them. 58 | StorageOverflow, 59 | } 60 | 61 | #[pallet::hooks] 62 | impl Hooks> for Pallet {} 63 | 64 | // Dispatchable functions allows users to interact with the pallet and invoke state changes. 65 | // These functions materialize as "extrinsics", which are often compared to transactions. 66 | // Dispatchable functions must be annotated with a weight and must return a DispatchResult. 67 | #[pallet::call] 68 | impl Pallet { 69 | /// An example dispatchable that takes a singles value as a parameter, writes the value to 70 | /// storage and emits an event. This function must be dispatched by a signed extrinsic. 71 | #[pallet::weight(10_000 + T::DbWeight::get().writes(1))] 72 | pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { 73 | // Check that the extrinsic was signed and get the signer. 74 | // This function will return an error if the extrinsic is not signed. 75 | // https://substrate.dev/docs/en/knowledgebase/runtime/origin 76 | let who = ensure_signed(origin)?; 77 | 78 | // Update storage. 79 | >::put(something); 80 | 81 | // Emit an event. 82 | Self::deposit_event(Event::SomethingStored(something, who)); 83 | // Return a successful DispatchResultWithPostInfo 84 | Ok(()) 85 | } 86 | 87 | /// An example dispatchable that may throw a custom error. 88 | #[pallet::weight(10_000 + T::DbWeight::get().reads_writes(1,1))] 89 | pub fn cause_error(origin: OriginFor) -> DispatchResult { 90 | let _who = ensure_signed(origin)?; 91 | 92 | // Read a value from storage. 93 | match >::get() { 94 | // Return an error if the value has not been set. 95 | None => Err(Error::::NoneValue)?, 96 | Some(old) => { 97 | // Increment the value read from storage; will error in the event of overflow. 98 | let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; 99 | // Update the value in storage with the incremented result. 100 | >::put(new); 101 | Ok(()) 102 | } 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /pallets/template/src/mock.rs: -------------------------------------------------------------------------------- 1 | use crate as pallet_template; 2 | use frame_support::parameter_types; 3 | use frame_system as system; 4 | use sp_core::H256; 5 | use sp_runtime::{ 6 | testing::Header, 7 | traits::{BlakeTwo256, IdentityLookup}, 8 | }; 9 | 10 | type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; 11 | type Block = frame_system::mocking::MockBlock; 12 | 13 | // Configure a mock runtime to test the pallet. 14 | frame_support::construct_runtime!( 15 | pub enum Test where 16 | Block = Block, 17 | NodeBlock = Block, 18 | UncheckedExtrinsic = UncheckedExtrinsic, 19 | { 20 | System: frame_system::{Pallet, Call, Config, Storage, Event}, 21 | TemplateModule: pallet_template::{Pallet, Call, Storage, Event}, 22 | } 23 | ); 24 | 25 | parameter_types! { 26 | pub const BlockHashCount: u64 = 250; 27 | pub const SS58Prefix: u8 = 42; 28 | } 29 | 30 | impl system::Config for Test { 31 | type BaseCallFilter = frame_support::traits::Everything; 32 | type BlockWeights = (); 33 | type BlockLength = (); 34 | type DbWeight = (); 35 | type Origin = Origin; 36 | type Call = Call; 37 | type Index = u64; 38 | type BlockNumber = u64; 39 | type Hash = H256; 40 | type Hashing = BlakeTwo256; 41 | type AccountId = u64; 42 | type Lookup = IdentityLookup; 43 | type Header = Header; 44 | type Event = Event; 45 | type BlockHashCount = BlockHashCount; 46 | type Version = (); 47 | type PalletInfo = PalletInfo; 48 | type AccountData = (); 49 | type OnNewAccount = (); 50 | type OnKilledAccount = (); 51 | type SystemWeightInfo = (); 52 | type SS58Prefix = SS58Prefix; 53 | type OnSetCode = (); 54 | } 55 | 56 | impl pallet_template::Config for Test { 57 | type Event = Event; 58 | } 59 | 60 | // Build genesis storage according to the mock runtime. 61 | pub fn new_test_ext() -> sp_io::TestExternalities { 62 | system::GenesisConfig::default().build_storage::().unwrap().into() 63 | } 64 | -------------------------------------------------------------------------------- /pallets/template/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::{mock::*, Error}; 2 | use frame_support::{assert_noop, assert_ok}; 3 | 4 | #[test] 5 | fn it_works_for_default_value() { 6 | new_test_ext().execute_with(|| { 7 | // Dispatch a signed extrinsic. 8 | assert_ok!(TemplateModule::do_something(Origin::signed(1), 42)); 9 | // Read pallet storage and assert an expected result. 10 | assert_eq!(TemplateModule::something(), Some(42)); 11 | }); 12 | } 13 | 14 | #[test] 15 | fn correct_error_for_none_value() { 16 | new_test_ext().execute_with(|| { 17 | // Ensure the expected error is thrown when no value is present. 18 | assert_noop!( 19 | TemplateModule::cause_error(Origin::signed(1)), 20 | Error::::NoneValue 21 | ); 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /pallets/utxo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pallet-utxo" 3 | version = "0.1.0" 4 | authors = ["BCarlaYap <2826165+BCarlaYap@users.noreply.github.com>"] 5 | edition = "2018" 6 | 7 | [features] 8 | runtime-benchmarks = ["frame-benchmarking"] 9 | default = ['std'] 10 | std = [ 11 | 'codec/std', 12 | 'frame-support/std', 13 | 'frame-system/std', 14 | 'frame-benchmarking/std', 15 | 'chainscript/std', 16 | 'pallet-timestamp/std', 17 | 'sp-core/std', 18 | 'sp-std/std', 19 | ] 20 | 21 | [dependencies] 22 | hex-literal = "0.2.1" 23 | log = "0.4.8" 24 | serde = '1.0.119' 25 | variant_count = '1.1' 26 | 27 | [dev-dependencies] 28 | rand = "0.4" 29 | 30 | [dependencies.bech32] 31 | default-features = false 32 | path = '../../libs/bech32' 33 | version = '0.8.1' 34 | 35 | [dependencies.base58_nostd] 36 | default-features = false 37 | path = '../../libs/base58_nostd' 38 | version = '0.1.0' 39 | 40 | [dependencies.chainscript] 41 | default-features = false 42 | path = '../../libs/chainscript' 43 | version = '0.1.0' 44 | 45 | [dependencies.codec] 46 | default-features = false 47 | features = ["derive", "chain-error"] 48 | package = 'parity-scale-codec' 49 | version = '2.0.0' 50 | 51 | [dependencies.pp-api] 52 | default-features = false 53 | path = "../../traits/pp-api/" 54 | 55 | [dependencies.utxo-api] 56 | default-features = false 57 | path = "../../traits/utxo-api/" 58 | 59 | [dependencies.frame-benchmarking] 60 | default-features = false 61 | git = 'https://github.com/paritytech/substrate.git' 62 | optional = true 63 | version = '4.0.0-dev' 64 | branch = "master" 65 | 66 | [dependencies.frame-support] 67 | default-features = false 68 | git = 'https://github.com/paritytech/substrate.git' 69 | version = '4.0.0-dev' 70 | branch = "master" 71 | 72 | [dependencies.frame-system] 73 | default-features = false 74 | git = 'https://github.com/paritytech/substrate.git' 75 | version = '4.0.0-dev' 76 | branch = "master" 77 | 78 | [dependencies.pallet-authorship] 79 | default-features = false 80 | git = 'https://github.com/paritytech/substrate.git' 81 | version = '4.0.0-dev' 82 | branch = "master" 83 | 84 | [dependencies.pallet-timestamp] 85 | default-features = false 86 | git = 'https://github.com/paritytech/substrate.git' 87 | branch = "master" 88 | version = '4.0.0-dev' 89 | 90 | [dependencies.sp-core] 91 | default-features = false 92 | git = 'https://github.com/paritytech/substrate.git' 93 | version = '4.0.0-dev' 94 | branch = "master" 95 | 96 | [dependencies.sp-std] 97 | default-features = false 98 | git = 'https://github.com/paritytech/substrate.git' 99 | version = '4.0.0-dev' 100 | branch = "master" 101 | 102 | [dependencies.sp-runtime] 103 | default-features = false 104 | git = 'https://github.com/paritytech/substrate.git' 105 | version = '4.0.0-dev' 106 | branch = "master" 107 | 108 | [dev-dependencies.sp-keystore] 109 | version = "0.10.0-dev" 110 | git = 'https://github.com/paritytech/substrate.git' 111 | branch = "master" 112 | 113 | [dev-dependencies.proptest] 114 | version = "1.0.0" -------------------------------------------------------------------------------- /pallets/utxo/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 RBB S.r.l 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pallets/utxo/rpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pallet-utxo-rpc" 3 | version = "0.1.0" 4 | authors = ["RBB Lab"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | pallet-utxo-rpc-runtime-api = { path = "./runtime-api" } 9 | jsonrpc-core = "18.0.0" 10 | jsonrpc-core-client = "18.0.0" 11 | jsonrpc-derive = "18.0.0" 12 | 13 | [dependencies.serde] 14 | version = "1.0.119" 15 | features = ["derive"] 16 | 17 | [dependencies.sp-blockchain] 18 | default_features = false 19 | git = 'https://github.com/paritytech/substrate.git' 20 | version = '4.0.0-dev' 21 | branch = "master" 22 | 23 | [dependencies.codec] 24 | package = "parity-scale-codec" 25 | version = "2.0.0" 26 | default-features = false 27 | features = ["derive"] 28 | 29 | [dependencies.sp-api] 30 | default-features = false 31 | git = 'https://github.com/paritytech/substrate.git' 32 | version = '4.0.0-dev' 33 | branch = "master" 34 | 35 | [dependencies.sp-runtime] 36 | default-features = false 37 | git = 'https://github.com/paritytech/substrate.git' 38 | version = '4.0.0-dev' 39 | branch = "master" 40 | 41 | [dependencies.frame-support] 42 | default-features = false 43 | git = 'https://github.com/paritytech/substrate.git' 44 | version = '4.0.0-dev' 45 | branch = "master" 46 | 47 | [dependencies.sp-core] 48 | default-features = false 49 | git = 'https://github.com/paritytech/substrate.git' 50 | version = '4.0.0-dev' 51 | branch = "master" -------------------------------------------------------------------------------- /pallets/utxo/rpc/README.md: -------------------------------------------------------------------------------- 1 | # UTXO RPC interface 2 | 3 | TODO document calls and add examples 4 | -------------------------------------------------------------------------------- /pallets/utxo/rpc/runtime-api/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pallet-utxo-rpc-runtime-api" 3 | version = "0.1.0" 4 | authors = ["RBB Lab"] 5 | edition = "2018" 6 | 7 | [dependencies.serde] 8 | version = "1.0.104" 9 | optional = true 10 | features = ["derive"] 11 | 12 | [dependencies.codec] 13 | package = "parity-scale-codec" 14 | version = "2.0.0" 15 | default-features = false 16 | features = ["derive"] 17 | 18 | [dependencies.sp-api] 19 | default-features = false 20 | git = 'https://github.com/paritytech/substrate.git' 21 | version = '4.0.0-dev' 22 | branch = "master" 23 | 24 | [dependencies.sp-runtime] 25 | default-features = false 26 | git = 'https://github.com/paritytech/substrate.git' 27 | version = '4.0.0-dev' 28 | branch = "master" 29 | 30 | [dependencies.frame-support] 31 | default-features = false 32 | git = 'https://github.com/paritytech/substrate.git' 33 | version = '4.0.0-dev' 34 | branch = "master" 35 | 36 | [dependencies.sp-core] 37 | default-features = false 38 | git = 'https://github.com/paritytech/substrate.git' 39 | version = '4.0.0-dev' 40 | branch = "master" 41 | 42 | [dev-dependencies] 43 | serde_json = "1.0.48" 44 | 45 | [features] 46 | default = ["std"] 47 | std = [ 48 | "serde", 49 | "sp-api/std", 50 | "codec/std", 51 | "sp-runtime/std", 52 | "frame-support/std", 53 | ] 54 | try-runtime = ['frame-support/try-runtime'] 55 | -------------------------------------------------------------------------------- /pallets/utxo/rpc/runtime-api/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 RBB S.r.l 2 | // opensource@mintlayer.org 3 | // SPDX-License-Identifier: MIT 4 | // Licensed under the MIT License; 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://spdx.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Author(s): A. Altonen, Anton Sinitsyn 17 | #![cfg_attr(not(feature = "std"), no_std)] 18 | 19 | sp_api::decl_runtime_apis! { 20 | pub trait UtxoApi { 21 | fn send() -> u32; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pallets/utxo/rpc/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 RBB S.r.l 2 | // opensource@mintlayer.org 3 | // SPDX-License-Identifier: MIT 4 | // Licensed under the MIT License; 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://spdx.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Author(s): A. Altonen, A. Sinitsyn 17 | 18 | use jsonrpc_core::{Error as RpcError, ErrorCode, Result}; 19 | use jsonrpc_derive::rpc; 20 | pub use pallet_utxo_rpc_runtime_api::UtxoApi as UtxoRuntimeApi; 21 | use sp_api::ProvideRuntimeApi; 22 | use sp_blockchain::HeaderBackend; 23 | use sp_runtime::{generic::BlockId, traits::Block as BlockT}; 24 | use std::sync::Arc; 25 | 26 | #[rpc] 27 | pub trait UtxoApi { 28 | #[rpc(name = "utxo_send")] 29 | fn send(&self, at: Option) -> Result; 30 | } 31 | 32 | /// A struct that implements the [`UtxoApi`]. 33 | pub struct Utxo { 34 | client: Arc, 35 | _marker: std::marker::PhantomData, 36 | } 37 | 38 | impl Utxo { 39 | /// Create new `Utxo` instance with the given reference to the client. 40 | pub fn new(client: Arc) -> Self { 41 | Self { 42 | client, 43 | _marker: Default::default(), 44 | } 45 | } 46 | } 47 | 48 | /// Error type of this RPC API. 49 | pub enum Error { 50 | /// The transaction was not decodable. 51 | DecodeError = 1, 52 | /// The call to runtime failed. 53 | RuntimeError = 2, 54 | /// The access to Storage failed 55 | StorageError = 3, 56 | } 57 | 58 | impl UtxoApi<::Hash> for Utxo 59 | where 60 | Block: BlockT, 61 | C: Send + Sync + 'static, 62 | C: ProvideRuntimeApi, 63 | C: HeaderBackend, 64 | C::Api: UtxoRuntimeApi, 65 | { 66 | fn send(&self, at: Option<::Hash>) -> Result { 67 | let api = self.client.runtime_api(); 68 | let at = BlockId::hash(at.unwrap_or_else(|| 69 | // If the block hash is not supplied assume the best block. 70 | self.client.info().best_hash)); 71 | 72 | api.send(&at).map_err(|e| RpcError { 73 | code: ErrorCode::ServerError(Error::RuntimeError as i64), 74 | message: "Unable to query dispatch info.".into(), 75 | data: Some(format!("{:?}", e).into()), 76 | }) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /pallets/utxo/src/benchmarking.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 RBB S.r.l 2 | // opensource@mintlayer.org 3 | // SPDX-License-Identifier: MIT 4 | // Licensed under the MIT License; 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://spdx.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Author(s): C. Yap 17 | 18 | use super::*; 19 | 20 | use crate::{Pallet as Utxo, Transaction, TransactionInput, TransactionOutput}; 21 | use codec::Encode; 22 | use frame_benchmarking::{benchmarks, whitelisted_caller}; 23 | use frame_system::{EventRecord, RawOrigin}; 24 | use hex_literal::hex; 25 | use sp_core::{sp_std::vec, sr25519::Public, testing::SR25519, H256, H512}; 26 | 27 | fn assert_last_event(generic_event: ::Event) { 28 | let events = frame_system::Pallet::::events(); 29 | let system_event: ::Event = generic_event.into(); 30 | 31 | let EventRecord { event, .. } = &events[events.len() - 1]; 32 | assert_eq!(event, &system_event); 33 | } 34 | 35 | benchmarks! { 36 | // only for test 37 | test_spend { 38 | // 5Gq2jqhDKtUScUzm9yCJGDDnhYQ8QHuMWiEzzKpjxma9n57R 39 | let alice_h256 = H256::from([ 40 | 210, 191, 75, 132, 77, 254, 253, 103, 114, 168, 41 | 132, 62, 102, 159, 148, 52, 8, 150, 106, 151, 126, 42 | 58, 226, 175, 29, 215, 142, 15, 85, 244, 223, 103 43 | ]); 44 | let alice_pub_key = Public::from_h256(alice_h256.clone()); 45 | 46 | let genesis_utxo = hex!("931fe49afe365072e71771cd99e13cfb54fa28fad479e23556ff9de6a3dd19a9"); 47 | let genesis_utxo = H256::from(genesis_utxo); 48 | 49 | let mut tx = Transaction { 50 | inputs: vec![TransactionInput { 51 | outpoint: genesis_utxo, 52 | sig_script: H512::zero(), 53 | }], 54 | outputs: vec![TransactionOutput::new(50, alice_h256)], 55 | }; 56 | 57 | let alice_sig = frame_support::sp_io::crypto::sr25519_sign(SR25519, &alice_pub_key, &tx.encode()).unwrap(); 58 | 59 | tx.inputs[0].sig_script = H512::from(alice_sig); 60 | 61 | let caller: T::AccountId = whitelisted_caller(); 62 | }: spend(RawOrigin::Signed(caller),tx.clone()) 63 | verify { 64 | assert_last_event::(Event::TransactionSuccess(tx).into()); 65 | assert_eq!(RewardTotal::::get(),50u128); 66 | assert!(!UtxoStore::::contains_key(genesis_utxo)); 67 | } 68 | 69 | runtime_spend { 70 | /// ran using mintlayer-node. 71 | // 0x76584168d10a20084082ed80ec71e2a783abbb8dd6eb9d4893b089228498e9ff 72 | let alice_h256 = H256::from([ 73 | 212, 53, 147, 199, 21, 253, 211, 28, 97, 20, 26, 74 | 189, 4, 169, 159, 214,130, 44, 133,88, 133, 76, 75 | 205, 227, 154, 86, 132, 231, 165, 109, 162, 125] 76 | ); 77 | let alice_pub_key = Public::from_h256(alice_h256.clone()); 78 | 79 | let genesis_utxo = H256::from([ 80 | 81, 21, 116, 75, 236, 124, 214, 180, 35, 127, 81, 81 | 208, 154, 106, 21, 216, 89, 10, 92, 139, 45, 15, 82 | 227, 227, 206, 59, 82, 197, 34, 147, 181, 76] 83 | ); 84 | 85 | // 0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48 86 | let bob_h256 = H256::from([ 87 | 142, 175, 4, 21, 22, 135, 115, 99, 38, 201, 254, 161, 88 | 126, 37, 252, 82, 135, 97, 54, 147, 201, 18, 144, 156, 89 | 178, 38, 170, 71, 148, 242, 106, 72] 90 | ); 91 | let bob_pub_key = Public::from_h256(bob_h256.clone()); 92 | 93 | // 0x52ffd490c6b266edc96278e7dee680f0bc2454653f2eab823b8d2ec13289d770c7e0a041f32039b7f73b393f3bdd7b09295b56610b59e2165e3d34d83c9ca98f 94 | let alice_sigscript = H512::from([ 95 | 82, 255, 212, 144, 198, 178, 102, 237, 201, 98, 120, 96 | 231, 222, 230, 128, 240, 188, 36, 84, 101, 63, 46, 97 | 171, 130, 59, 141, 46, 193, 50, 137, 215, 112, 199, 98 | 224, 160, 65, 243, 32, 57, 183, 247, 59, 57, 63, 59, 99 | 221, 123, 9, 41, 91, 86, 97, 11, 89, 226, 22, 94, 61, 100 | 52, 216, 60, 156, 169, 143] 101 | ); 102 | 103 | let mut tx = Transaction { 104 | inputs: vec![ TransactionInput { 105 | outpoint: genesis_utxo.clone(), 106 | sig_script: H512::zero() 107 | }], 108 | outputs: vec![ TransactionOutput::new(50, bob_h256)] 109 | }; 110 | 111 | tx.inputs[0].sig_script = alice_sigscript; 112 | 113 | let caller: T::AccountId = whitelisted_caller(); 114 | }: spend(RawOrigin::Signed(caller), tx.clone()) 115 | verify { 116 | assert_last_event::(Event::TransactionSuccess(tx).into()); 117 | assert_eq!(RewardTotal::::get(),50u128); 118 | assert!(!UtxoStore::::contains_key(genesis_utxo)); 119 | } 120 | } 121 | 122 | // only for test 123 | #[cfg(test)] 124 | mod tests { 125 | use super::*; 126 | use crate::mock::{alice_test_ext, Test}; 127 | use frame_support::assert_ok; 128 | 129 | #[test] 130 | fn spend() { 131 | alice_test_ext().execute_with(|| { 132 | assert_ok!(test_benchmark_test_spend::()); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /pallets/utxo/src/tokens.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | use crate::{TransactionInput, MLT_UNIT}; 4 | use base58_nostd::{FromBase58, FromBase58Error, ToBase58, TOKEN_ID_PREFIX}; 5 | use codec::{Decode, Encode}; 6 | use frame_support::ensure; 7 | use frame_support::{dispatch::Vec, RuntimeDebug}; 8 | #[cfg(feature = "std")] 9 | use serde::{Deserialize, Serialize}; 10 | use sp_core::Hasher; 11 | use sp_core::H160; 12 | use sp_runtime::traits::BlakeTwo256; 13 | use sp_std::vec; 14 | 15 | const LENGTH_BYTES_TO_REPRESENT_ID: usize = 20; 16 | 17 | pub type Value = u128; 18 | 19 | pub struct Mlt(pub Value); 20 | impl Mlt { 21 | pub fn to_munit(&self) -> Value { 22 | self.0 * MLT_UNIT 23 | } 24 | } 25 | 26 | #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] 27 | #[derive(Clone, Encode, Decode, Eq, PartialEq, PartialOrd, Ord, RuntimeDebug)] 28 | pub struct TokenId { 29 | inner: H160, 30 | } 31 | 32 | impl TokenId { 33 | // Token id depends on signed or unsigned the same input 34 | pub fn new(first_input: &TransactionInput) -> TokenId { 35 | let first_input_hash = BlakeTwo256::hash(first_input.encode().as_slice()); 36 | TokenId { 37 | // We are loosing the first bytes of H256 over here and using 20 the last bytes 38 | inner: H160::from(first_input_hash), 39 | } 40 | } 41 | 42 | pub fn to_string(&self) -> Vec { 43 | self.inner.as_bytes().to_mls_b58check(Some(vec![TOKEN_ID_PREFIX])).to_vec() 44 | } 45 | 46 | pub fn from_string(data: &str) -> Result { 47 | let data = data.from_mls_b58check(Some(vec![TOKEN_ID_PREFIX])).map_err(|x| match x { 48 | FromBase58Error::InvalidBase58Character { .. } => "Invalid Base58 character", 49 | FromBase58Error::InvalidBase58Length => "Invalid Base58 length", 50 | FromBase58Error::InvalidChecksum => "Invalid checksum", 51 | FromBase58Error::InvalidPrefix => "Invalid token id", 52 | })?; 53 | Ok(TokenId { 54 | inner: TokenId::hash160_from_bytes(data.as_slice())?, 55 | }) 56 | } 57 | 58 | fn hash160_from_bytes(bytes: &[u8]) -> Result { 59 | ensure!( 60 | bytes.len() == LENGTH_BYTES_TO_REPRESENT_ID, 61 | "Unexpected length of the asset ID" 62 | ); 63 | let mut buffer = [0u8; 20]; 64 | buffer.copy_from_slice(bytes); 65 | Ok(H160::from(buffer)) 66 | } 67 | } 68 | 69 | #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] 70 | #[derive(Clone, Encode, Decode, Eq, PartialEq, PartialOrd, Ord, RuntimeDebug)] 71 | pub enum OutputData { 72 | // TokenTransfer data to another user. If it is a token, then the token data must also be transferred to the recipient. 73 | #[codec(index = 1)] 74 | TokenTransferV1 { token_id: TokenId, amount: Value }, 75 | // A new token creation 76 | #[codec(index = 2)] 77 | TokenIssuanceV1 { 78 | // token_id: TokenId, 79 | token_ticker: Vec, 80 | amount_to_issue: Value, 81 | // Should be not more than 18 numbers 82 | number_of_decimals: u8, 83 | metadata_uri: Vec, 84 | }, 85 | // todo: This part isn't fully tested, left for the next PR 86 | 87 | // // Burning a token or NFT 88 | // #[codec(index = 3)] 89 | // TokenBurnV1 { 90 | // token_id: TokenId, 91 | // amount_to_burn: Value, 92 | // }, 93 | // // A new NFT creation 94 | // #[codec(index = 4)] 95 | // NftMintV1 { 96 | // token_id: TokenId, 97 | // data_hash: NftDataHash, 98 | // metadata_uri: Vec, 99 | // }, 100 | } 101 | 102 | // todo: This part isn't fully tested, left for the next PR 103 | // #[cfg_attr(feature = "std", derive(Serialize, Deserialize))] 104 | // #[derive(Clone, Encode, Decode, Eq, PartialEq, PartialOrd, Ord, RuntimeDebug)] 105 | // pub enum NftDataHash { 106 | // #[codec(index = 1)] 107 | // Hash32([u8; 32]), 108 | // #[codec(index = 2)] 109 | // Raw(Vec), 110 | // // Or any type that you want to implement 111 | // } 112 | 113 | impl OutputData { 114 | pub(crate) fn id(&self, first_input: &TransactionInput) -> Option { 115 | match self { 116 | OutputData::TokenTransferV1 { ref token_id, .. } => Some(token_id.clone()), 117 | // OutputData::NftMintV1 { .. } | 118 | OutputData::TokenIssuanceV1 { .. } => Some(TokenId::new(first_input)), 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /pallets/utxo/src/weights.rs: -------------------------------------------------------------------------------- 1 | //! Autogenerated weights for pallet_utxo 2 | //! 3 | //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 4 | //! DATE: 2021-06-21, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` 5 | //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 6 | 7 | // Executed Command: 8 | // target/release/node-template 9 | // benchmark 10 | // --chain 11 | // dev 12 | // --execution=wasm 13 | // --wasm-execution=compiled 14 | // --pallet 15 | // pallet_utxo 16 | // --extrinsic 17 | // spend 18 | // --steps 19 | // 50 20 | // --repeat 21 | // 20 22 | // --output 23 | // . 24 | // --raw 25 | 26 | #![allow(unused_parens)] 27 | #![allow(unused_imports)] 28 | 29 | use frame_support::{traits::Get, weights::Weight}; 30 | use sp_core::sp_std::marker::PhantomData; 31 | 32 | /// Weight functions for pallet_utxo. 33 | pub struct WeightInfo(PhantomData); 34 | impl crate::WeightInfo for WeightInfo { 35 | fn spend(s: u32) -> Weight { 36 | (348_270_000 as Weight) 37 | // Standard Error: 2_000 38 | //TODO: literally just copying from substrate's 39 | .saturating_add((1_146_000 as Weight).saturating_mul(s as Weight)) 40 | .saturating_add(T::DbWeight::get().reads(3 as Weight)) 41 | .saturating_add(T::DbWeight::get().writes(3 as Weight)) 42 | } 43 | 44 | fn token_create(u: u32) -> Weight { 45 | // Under construction 46 | (u as Weight) 47 | .saturating_add((100 as Weight)) 48 | .saturating_add(T::DbWeight::get().reads(3 as Weight)) 49 | .saturating_add(T::DbWeight::get().writes(3 as Weight)) 50 | } 51 | 52 | fn send_to_address(s: u32) -> Weight { 53 | (348_270_000 as Weight) 54 | // Standard Error: 2_000 55 | //TODO: literally just copying from substrate's 56 | .saturating_add((1_146_000 as Weight).saturating_mul(s as Weight)) 57 | .saturating_add(T::DbWeight::get().reads(3 as Weight)) 58 | .saturating_add(T::DbWeight::get().writes(3 as Weight)) 59 | } 60 | 61 | //TODO this needs a benchmark 62 | fn unlock_request_for_withdrawal(s: u32) -> Weight { 63 | (548_270_000 as Weight) 64 | //TODO: literally just copying from substrate's 65 | .saturating_add((1_146_000 as Weight).saturating_mul(s as Weight)) 66 | .saturating_add(T::DbWeight::get().reads(3 as Weight)) 67 | .saturating_add(T::DbWeight::get().writes(3 as Weight)) 68 | } 69 | 70 | //TODO this needs a benchmark 71 | fn withdraw_stake(s: u32) -> Weight { 72 | (548_270_000 as Weight) 73 | //TODO: literally just copying from substrate's 74 | .saturating_add((1_146_000 as Weight).saturating_mul(s as Weight)) 75 | .saturating_add(T::DbWeight::get().reads(3 as Weight)) 76 | .saturating_add(T::DbWeight::get().writes(3 as Weight)) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /runtime/build.rs: -------------------------------------------------------------------------------- 1 | use substrate_wasm_builder::WasmBuilder; 2 | 3 | fn main() { 4 | WasmBuilder::new() 5 | .with_current_project() 6 | .export_heap_base() 7 | .import_memory() 8 | .build() 9 | } 10 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 100 2 | hard_tabs = false 3 | tab_spaces = 4 4 | array_width = 80 5 | chain_width = 80 6 | single_line_if_else_max_width = 50 7 | newline_style = "Unix" 8 | edition = "2018" 9 | -------------------------------------------------------------------------------- /scripts/docker_run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | echo "*** Start Substrate node template ***" 6 | 7 | cd $(dirname ${BASH_SOURCE[0]})/.. 8 | 9 | docker-compose down --remove-orphans 10 | docker-compose run --rm --service-ports dev $@ -------------------------------------------------------------------------------- /scripts/init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # This script is meant to be run on Unix/Linux based systems 3 | set -e 4 | 5 | echo "*** Initializing WASM build environment" 6 | 7 | if [ -z $CI_PROJECT_NAME ] ; then 8 | rustup update nightly 9 | rustup update stable 10 | fi 11 | 12 | rustup target add wasm32-unknown-unknown --toolchain nightly 13 | -------------------------------------------------------------------------------- /template.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 RBB S.r.l 2 | // opensource@mintlayer.org 3 | // SPDX-License-Identifier: MIT 4 | // Licensed under the MIT License; 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://spdx.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Author(s): B. Marsh 17 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | --- Still incomplete --- 2 | 3 | Functional tests system for Mintlayer 4 | 5 | To run the test: 6 | 7 | 1. Make sure substrate-interface python package is installed, preferably, use this command for installation: 8 | ``` 9 | python -m pip install 'substrate-interface == 0.13.12' 10 | python -m pip install 'scalecodec == 0.11.18' 11 | ``` 12 | 2. compile Mintlayer 13 | 3. run the `test_runner.py` 14 | 15 | You can choose the test you want by putting it as an argument to test runner. For example `test_runner.py example_test.py` 16 | 17 | -------------------------------------------------------------------------------- /test/config.ini.in: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2013-2016 The Bitcoin Core developers 2 | # Distributed under the MIT software license, see the accompanying 3 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 | 5 | # These environment variables are set by the build process and read by 6 | # test/functional/test_runner.py and test/util/bitcoin-util-test.py 7 | 8 | [environment] 9 | SRCDIR=@abs_top_srcdir@ 10 | BUILDDIR=@abs_top_builddir@ 11 | EXEEXT=@EXEEXT@ 12 | 13 | [components] 14 | # Which components are enabled. These are commented out by `configure` if they were disabled when running config. 15 | ENABLE_NODE=true 16 | -------------------------------------------------------------------------------- /test/functional/code.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mintlayer/core/bb38d9bbaa53960636548a926505812a80890ec4/test/functional/code.wasm -------------------------------------------------------------------------------- /test/functional/custom-types.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtime_id": 2, 3 | "types": { 4 | "Value": "u128", 5 | "DestinationCreatePP": { 6 | "type": "struct", 7 | "type_mapping": [ 8 | [ "code", "Vec" ], 9 | [ "data", "Vec" ] 10 | ] 11 | }, 12 | "DestinationCallPP": { 13 | "type": "struct", 14 | "type_mapping": [ 15 | [ "dest_account", "AccountId" ], 16 | [ "fund", "bool" ], 17 | [ "input_data", "Vec" ] 18 | ] 19 | }, 20 | "DestinationStake": { 21 | "type": "struct", 22 | "type_mapping": [ 23 | [ "stash_account", "AccountId" ], 24 | [ "controller_account", "AccountId" ], 25 | [ "session_key", "Vec" ] 26 | ] 27 | }, 28 | "DestinationStakeExtra": { 29 | "type": "struct", 30 | "type_mapping": [ 31 | [ "stash_account", "AccountId" ], 32 | [ "controller_account", "AccountId" ] 33 | ] 34 | }, 35 | "Destination": { 36 | "type": "enum", 37 | "type_mapping": [ 38 | [ "Pubkey", "Pubkey" ], 39 | [ "CreatePP", "DestinationCreatePP" ], 40 | [ "CallPP", "DestinationCallPP" ], 41 | [ "ScriptHash", "H256"], 42 | [ "LockForStaking", "DestinationStake" ], 43 | [ "LockExtraForStaking", "DestinationStakeExtra" ] 44 | ] 45 | }, 46 | "NftDataHash": { 47 | "type": "struct", 48 | "type_mapping": [ 49 | [ "Hash32", "[u8; 32]" ], 50 | [ "Raw", "Vec" ] 51 | ] 52 | }, 53 | "TokenId": { 54 | "type": "struct", 55 | "type_mapping": [ 56 | [ "inner", "H160" ] 57 | ] 58 | }, 59 | "TokenTransferV1": { 60 | "type": "struct", 61 | "type_mapping": [ 62 | [ "token_id", "TokenId" ], 63 | [ "amount", "Value" ] 64 | ] 65 | }, 66 | "TokenIssuanceV1": { 67 | "type": "struct", 68 | "type_mapping": [ 69 | [ "token_ticker", "Vec" ], 70 | [ "amount_to_issue", "Value" ], 71 | [ "number_of_decimals", "u8" ], 72 | [ "metadata_uri", "Vec" ] 73 | ] 74 | }, 75 | "TokenBurnV1": { 76 | "type": "struct", 77 | "type_mapping": [ 78 | [ "token_id", "TokenId" ], 79 | [ "amount_to_burn", "Value" ] 80 | ] 81 | }, 82 | "NftMintV1": { 83 | "type": "struct", 84 | "type_mapping": [ 85 | [ "token_id", "TokenId" ], 86 | [ "data_hash", "NftDataHash" ], 87 | [ "metadata_uri", "Vec" ] 88 | ] 89 | }, 90 | "OutputData": { 91 | "type": "enum", 92 | "type_mapping": [ 93 | [ "TokenTransfer", "TokenTransferV1" ], 94 | [ "TokenIssuance", "TokenIssuanceV1" ], 95 | [ "TokenBurn", "TokenBurnV1" ], 96 | [ "NftMint", "NftMintV1" ] 97 | ] 98 | }, 99 | "TransactionInput": { 100 | "type": "struct", 101 | "type_mapping": [ 102 | [ "outpoint", "Hash" ], 103 | [ "lock", "Vec" ], 104 | [ "witness", "Vec" ] 105 | ] 106 | }, 107 | "TransactionOutput": { 108 | "type": "struct", 109 | "type_mapping": [ 110 | [ "value", "Value" ], 111 | [ "destination", "Destination" ], 112 | [ "data", "Option"] 113 | ] 114 | }, 115 | "Transaction": { 116 | "type": "struct", 117 | "type_mapping": [ 118 | [ "inputs", "Vec" ], 119 | [ "outputs", "Vec" ], 120 | [ "time_lock", "Compact" ] 121 | ] 122 | }, 123 | "Outpoint": { 124 | "type": "struct", 125 | "type_mapping": [ 126 | [ "transaction", "Transaction" ], 127 | [ "index", "u64" ] 128 | ] 129 | }, 130 | "TransactionOutputFor": "TransactionOutput", 131 | "TransactionFor": "Transaction", 132 | "Address": "MultiAddress", 133 | "LookupSource": "MultiAddress", 134 | "Value": "u128", 135 | "value": "Value", 136 | "pub_key": "H256", 137 | "Difficulty": "U256", 138 | "DifficultyAndTimestamp": { 139 | "type": "struct", 140 | "type_mapping": [ 141 | ["difficulty", "Difficulty"], 142 | ["timestamp", "Moment"] 143 | ] 144 | }, 145 | "Pubkey": "H256", 146 | "Public": "H256", 147 | "SignatureData": { 148 | "type": "struct", 149 | "type_mapping": [ 150 | [ "sighash", "u8" ], 151 | [ "inputs", "SignatureDataInputs" ], 152 | [ "outputs", "SignatureDataOutputs" ], 153 | [ "time_lock", "u64" ], 154 | [ "codesep_pos", "u32" ] 155 | ] 156 | }, 157 | "SignatureDataInputs": { 158 | "type": "enum", 159 | "type_mapping": [ 160 | [ "SpecifiedPay", "(H256, H256, u64)" ], 161 | [ "AnyoneCanPay", "(H256, H256)" ] 162 | ] 163 | }, 164 | "SignatureDataOutputs": { 165 | "type": "enum", 166 | "type_mapping": [ 167 | [ "Unused", "()" ], 168 | [ "All", "H256" ], 169 | [ "None", "()" ], 170 | [ "Single", "H256" ] 171 | ] 172 | } 173 | }, 174 | "versioning": [ ] 175 | } 176 | -------------------------------------------------------------------------------- /test/functional/example_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2021 RBB S.r.l 3 | # Copyright (c) 2017 The Bitcoin Core developers 4 | # Distributed under the MIT software license, see the accompanying 5 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 6 | """An example functional test 7 | 8 | The module-level docstring should include a high-level description of 9 | what the test is doing. It's the first thing people see when they open 10 | the file and should give the reader information about *what* the test 11 | is testing and *how* it's being tested 12 | """ 13 | # Imports should be in PEP8 ordering (std library first, then third party 14 | # libraries then local imports). 15 | from collections import defaultdict 16 | 17 | from substrateinterface import Keypair 18 | import test_framework.mintlayer.utxo as utxo 19 | 20 | # Avoid wildcard * imports if possible 21 | # from test_framework.blocktools import (create_block, create_coinbase) 22 | # from test_framework.mininode import ( 23 | # CInv, 24 | # P2PInterface, 25 | # mininode_lock, 26 | # msg_block, 27 | # msg_getdata, 28 | # network_thread_join, 29 | # network_thread_start, 30 | # ) 31 | from test_framework.test_framework import MintlayerTestFramework 32 | from test_framework.util import ( 33 | assert_equal, 34 | connect_nodes, 35 | wait_until, 36 | ) 37 | 38 | 39 | class ExampleTest(MintlayerTestFramework): 40 | # Each functional test is a subclass of the MintlayerTestFramework class. 41 | 42 | # Override the set_test_params(), add_options(), setup_chain(), setup_network() 43 | # and setup_nodes() methods to customize the test setup as required. 44 | 45 | def set_test_params(self): 46 | """Override test parameters for your individual test. 47 | 48 | This method must be overridden and num_nodes must be exlicitly set.""" 49 | self.setup_clean_chain = True 50 | self.num_nodes = 3 51 | # Use self.extra_args to change command-line arguments for the nodes 52 | self.extra_args = [[], [], []] 53 | 54 | # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() 55 | 56 | # Use add_options() to add specific command-line options for your test. 57 | # In practice this is not used very much, since the tests are mostly written 58 | # to be run in automated environments without command-line options. 59 | # def add_options() 60 | # pass 61 | 62 | # Use setup_chain() to customize the node data directories. In practice 63 | # this is not used very much since the default behaviour is almost always 64 | # fine 65 | # def setup_chain(): 66 | # pass 67 | 68 | def setup_network(self): 69 | """Setup the test network topology 70 | 71 | Often you won't need to override this, since the standard network topology 72 | (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests. 73 | 74 | If you do override this method, remember to start the nodes, assign 75 | them to self.nodes, connect them and then sync.""" 76 | 77 | self.setup_nodes() 78 | 79 | # In this test, we're not connecting node2 to node0 or node1. Calls to 80 | # sync_all() should not include node2, since we're not expecting it to 81 | # sync. 82 | connect_nodes(self.nodes[0], self.nodes[1]) 83 | # self.sync_all([self.nodes[0:1]]) 84 | 85 | # Use setup_nodes() to customize the node start behaviour (for example if 86 | # you don't want to start all nodes at the start of the test). 87 | # def setup_nodes(): 88 | # pass 89 | 90 | def custom_method(self): 91 | """Do some custom behaviour for this test 92 | 93 | Define it in a method here because you're going to use it repeatedly. 94 | If you think it's useful in general, consider moving it to the base 95 | MintlayerTestFramework class so other tests can use it.""" 96 | 97 | self.log.info("Running custom_method") 98 | 99 | def run_test(self): 100 | """Main test logic""" 101 | client = self.nodes[0].rpc_client 102 | 103 | alice = Keypair.create_from_uri('//Alice') 104 | 105 | # Find an utxo with enough funds 106 | utxos = [u for u in client.utxos_for(alice) if u[1].value >= 150] 107 | 108 | tx1 = utxo.Transaction( 109 | client, 110 | inputs=[ 111 | utxo.Input(utxos[0][0]), 112 | ], 113 | outputs=[ 114 | utxo.Output( 115 | value=50, 116 | destination=utxo.DestPubkey(alice.public_key), 117 | data=None 118 | ), 119 | utxo.Output( 120 | value=100, 121 | destination=utxo.DestPubkey(alice.public_key), 122 | data=None 123 | ), 124 | # This output prevent reward overflow 125 | utxo.Output( 126 | value=3981553255926290448385, # genesis amount - u64::MAX 127 | destination=utxo.DestPubkey(alice.public_key), 128 | data=None 129 | ) 130 | 131 | ] 132 | ).sign(alice, [utxos[0][1]]) 133 | res = client.submit(alice, tx1) 134 | 135 | tx2 = utxo.Transaction( 136 | client, 137 | inputs=[ 138 | # spend the 100 utxo output (index 1) 139 | utxo.Input(tx1.outpoint(1)), 140 | ], 141 | outputs=[ 142 | utxo.Output( 143 | value=60, 144 | destination=utxo.DestPubkey(alice.public_key), 145 | data=None 146 | ), 147 | ] 148 | ).sign(alice, [tx1.outputs[1]]) 149 | client.submit(alice, tx2) 150 | 151 | 152 | if __name__ == '__main__': 153 | ExampleTest().main() 154 | -------------------------------------------------------------------------------- /test/functional/feature_alice_bob_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2021 RBB S.r.l 3 | # Copyright (c) 2017 The Bitcoin Core developers 4 | # Distributed under the MIT software license, see the accompanying 5 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 6 | """An example functional test 7 | 8 | Send a transaction from Alice to Bob, then spend Bob's transaction 9 | """ 10 | 11 | from substrateinterface import Keypair 12 | import test_framework.mintlayer.utxo as utxo 13 | 14 | from test_framework.test_framework import MintlayerTestFramework 15 | from test_framework.util import ( 16 | assert_equal, 17 | connect_nodes, 18 | wait_until, 19 | ) 20 | 21 | 22 | class ExampleTest(MintlayerTestFramework): 23 | # Each functional test is a subclass of the MintlayerTestFramework class. 24 | 25 | # Override the set_test_params(), add_options(), setup_chain(), setup_network() 26 | # and setup_nodes() methods to customize the test setup as required. 27 | 28 | def set_test_params(self): 29 | """Override test parameters for your individual test. 30 | 31 | This method must be overridden and num_nodes must be exlicitly set.""" 32 | self.setup_clean_chain = True 33 | self.num_nodes = 1 34 | # Use self.extra_args to change command-line arguments for the nodes 35 | self.extra_args = [[]] 36 | 37 | # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() 38 | 39 | def setup_network(self): 40 | """Setup the test network topology 41 | 42 | Often you won't need to override this, since the standard network topology 43 | (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests. 44 | 45 | If you do override this method, remember to start the nodes, assign 46 | them to self.nodes, connect them and then sync.""" 47 | 48 | self.setup_nodes() 49 | 50 | def custom_method(self): 51 | """Do some custom behaviour for this test 52 | 53 | Define it in a method here because you're going to use it repeatedly. 54 | If you think it's useful in general, consider moving it to the base 55 | MintlayerTestFramework class so other tests can use it.""" 56 | 57 | self.log.info("Running custom_method") 58 | 59 | def run_test(self): 60 | client = self.nodes[0].rpc_client 61 | 62 | alice = Keypair.create_from_uri('//Alice') 63 | bob = Keypair.create_from_uri('//Bob') 64 | 65 | # fetch the genesis utxo from storage 66 | utxos = list(client.utxos_for(alice)) 67 | 68 | tx1 = utxo.Transaction( 69 | client, 70 | inputs=[ 71 | utxo.Input(utxos[0][0]), 72 | ], 73 | outputs=[ 74 | utxo.Output( 75 | value=50, 76 | destination=utxo.DestPubkey(bob.public_key), 77 | data=None 78 | ), 79 | ] 80 | ).sign(alice, [utxos[0][1]]) 81 | client.submit(alice, tx1) 82 | 83 | tx2 = utxo.Transaction( 84 | client, 85 | inputs=[ 86 | utxo.Input(tx1.outpoint(0)), 87 | ], 88 | outputs=[ 89 | utxo.Output( 90 | value=30, 91 | destination=utxo.DestPubkey(alice.public_key), 92 | data=None 93 | ), 94 | utxo.Output( 95 | value=20, 96 | destination=utxo.DestPubkey(bob.public_key), 97 | data=None 98 | ), 99 | ] 100 | ).sign(bob, tx1.outputs) 101 | client.submit(bob, tx2) 102 | 103 | 104 | if __name__ == '__main__': 105 | ExampleTest().main() 106 | -------------------------------------------------------------------------------- /test/functional/feature_smart_contract_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2021 RBB S.r.l 3 | # Copyright (c) 2017 The Bitcoin Core developers 4 | # Distributed under the MIT software license, see the accompanying 5 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 6 | """Smart contract test 7 | 8 | """ 9 | # Imports should be in PEP8 ordering (std library first, then third party 10 | # libraries then local imports). 11 | from collections import defaultdict 12 | 13 | from substrateinterface import Keypair 14 | import test_framework.mintlayer.utxo as utxo 15 | import test_framework.mintlayer.contract as contract 16 | 17 | from test_framework.test_framework import MintlayerTestFramework 18 | from test_framework.util import ( 19 | assert_equal, 20 | connect_nodes, 21 | wait_until, 22 | ) 23 | 24 | import os 25 | 26 | 27 | class ExampleTest(MintlayerTestFramework): 28 | # Each functional test is a subclass of the MintlayerTestFramework class. 29 | 30 | # Override the set_test_params(), add_options(), setup_chain(), setup_network() 31 | # and setup_nodes() methods to customize the test setup as required. 32 | 33 | def set_test_params(self): 34 | """Override test parameters for your individual test. 35 | 36 | This method must be overridden and num_nodes must be exlicitly set.""" 37 | self.setup_clean_chain = True 38 | self.num_nodes = 3 39 | # Use self.extra_args to change command-line arguments for the nodes 40 | self.extra_args = [[], [], []] 41 | 42 | # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() 43 | 44 | def setup_network(self): 45 | """Setup the test network topology 46 | 47 | Often you won't need to override this, since the standard network topology 48 | (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests. 49 | 50 | If you do override this method, remember to start the nodes, assign 51 | them to self.nodes, connect them and then sync.""" 52 | 53 | self.setup_nodes() 54 | 55 | # In this test, we're not connecting node2 to node0 or node1. Calls to 56 | # sync_all() should not include node2, since we're not expecting it to 57 | # sync. 58 | connect_nodes(self.nodes[0], self.nodes[1]) 59 | # self.sync_all([self.nodes[0:1]]) 60 | 61 | def run_test(self): 62 | """Main test logic""" 63 | client = self.nodes[0].rpc_client 64 | 65 | substrate = client.substrate 66 | 67 | alice = Keypair.create_from_uri('//Alice') 68 | 69 | # Find a suitable UTXO 70 | initial_utxo = [x for x in client.utxos_for(alice) if x[1].value >= 50][0] 71 | 72 | tx0 = utxo.Transaction( 73 | client, 74 | inputs=[ 75 | utxo.Input(initial_utxo[0]), 76 | ], 77 | outputs=[ 78 | utxo.Output( 79 | value=50, 80 | destination=utxo.DestPubkey(alice.public_key), 81 | data=None 82 | ), 83 | utxo.Output( 84 | value=10, 85 | destination=utxo.DestCreatePP( 86 | code=os.path.join(os.path.dirname(__file__), "code.wasm"), 87 | data=[0xed, 0x4b, 0x9d, 0x1b], # default() constructor selector 88 | ), 89 | data=None 90 | ), 91 | # This output prevent reward overflow 92 | utxo.Output( 93 | value=3981553255926290448385, # = genesis amount - u64::MAX 94 | destination=utxo.DestPubkey(alice.public_key), 95 | data=None 96 | ) 97 | ] 98 | ).sign(alice, [initial_utxo[1]]) 99 | 100 | # submit transaction and get the extrinsic and block hashes 101 | (ext, blk,_) = client.submit(alice, tx0) 102 | 103 | # each new smart contract instantiation creates a new account 104 | # fetch this SS58-formatted account address and return it 105 | # and the hex-encoded account id 106 | (ss58, acc_id) = contract.getContractAddresses(substrate, blk) 107 | 108 | # create new contract instance which can be used to interact 109 | # with the instantiated contract 110 | contractInstance = contract.ContractInstance( 111 | ss58, 112 | os.path.join(os.path.dirname(__file__), "metadata.json"), 113 | substrate 114 | ) 115 | 116 | # read the value of the flipper contract 117 | result = contractInstance.read(alice, "get") 118 | assert_equal(result.contract_result_data.value, False) 119 | 120 | msg_data = contractInstance.generate_message_data("flip", {}) 121 | self.log.info("Contract msg_data: {}, {}, {}".format(ss58, acc_id, msg_data)) 122 | 123 | tx1 = utxo.Transaction( 124 | client, 125 | inputs=[ 126 | utxo.Input(tx0.outpoint(0)), 127 | ], 128 | outputs=[ 129 | utxo.Output( 130 | value=49, 131 | destination=utxo.DestPubkey(alice.public_key), 132 | data=None 133 | ), 134 | utxo.Output( 135 | value=1, 136 | destination=utxo.DestCallPP( 137 | dest_account=acc_id, 138 | fund=False, 139 | input_data=bytes.fromhex(msg_data.to_hex()[2:]), 140 | ), 141 | data=None 142 | ), 143 | ] 144 | ).sign(alice, [tx0.outputs[0]], [0]) 145 | (ext_hash, blk_hash,_) = client.submit(alice, tx1) 146 | 147 | result = contractInstance.read(alice, "get") 148 | assert_equal(result.contract_result_data.value, True) 149 | 150 | 151 | if __name__ == '__main__': 152 | ExampleTest().main() 153 | -------------------------------------------------------------------------------- /test/functional/feature_staking_diff_addresses.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2017 The Bitcoin Core developers 3 | # Distributed under the MIT software license, see the accompanying 4 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | """An example functional test 6 | 7 | Using Alice's utxo, Charlie and Dave stakes for the first time. 8 | """ 9 | 10 | from substrateinterface import Keypair 11 | import test_framework.mintlayer.utxo as utxo 12 | 13 | from test_framework.test_framework import MintlayerTestFramework 14 | from test_framework.util import ( 15 | assert_equal, 16 | connect_nodes, 17 | wait_until, 18 | ) 19 | from test_framework.messages import COIN 20 | 21 | 22 | class ExampleTest(MintlayerTestFramework): 23 | # Each functional test is a subclass of the MintlayerTestFramework class. 24 | 25 | # Override the set_test_params(), add_options(), setup_chain(), setup_network() 26 | # and setup_nodes() methods to customize the test setup as required. 27 | 28 | def set_test_params(self): 29 | """Override test parameters for your individual test. 30 | 31 | This method must be overridden and num_nodes must be exlicitly set.""" 32 | self.setup_clean_chain = True 33 | self.num_nodes = 2 34 | # Use self.extra_args to change command-line arguments for the nodes 35 | self.extra_args = [['--alice'],['--bob']] 36 | 37 | # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() 38 | 39 | def setup_network(self): 40 | """Setup the test network topology 41 | 42 | Often you won't need to override this, since the standard network topology 43 | (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests. 44 | 45 | If you do override this method, remember to start the nodes, assign 46 | them to self.nodes, connect them and then sync.""" 47 | 48 | self.setup_nodes() 49 | 50 | def custom_method(self): 51 | """Do some custom behaviour for this test 52 | 53 | Define it in a method here because you're going to use it repeatedly. 54 | If you think it's useful in general, consider moving it to the base 55 | MintlayerTestFramework class so other tests can use it.""" 56 | 57 | self.log.info("Running custom_method") 58 | 59 | def run_test(self): 60 | client = self.nodes[0].rpc_client 61 | 62 | alice = Keypair.create_from_uri('//Alice') 63 | 64 | charlie = Keypair.create_from_uri('//Charlie') 65 | charlie_stash = Keypair.create_from_uri('//Charlie//stash') 66 | 67 | dave = Keypair.create_from_uri('//Dave') 68 | dave_stash = Keypair.create_from_uri('//Dave//stash') 69 | 70 | # fetch the genesis utxo from storage 71 | utxos = list(client.utxos_for(alice)) 72 | 73 | # there's only 2 record of staking, which are alice and bob. 74 | assert_equal( len(list(client.staking_count())), 2 ) 75 | 76 | # charlie and dave are funded from alice but directly as stakers. 77 | tx1 = utxo.Transaction( 78 | client, 79 | inputs=[ 80 | utxo.Input(utxos[0][0]), 81 | ], 82 | outputs=[ 83 | utxo.Output( 84 | value=40000 * COIN, 85 | destination=utxo.DestLockForStaking(charlie_stash.public_key, charlie.public_key,'0x7e0dd8c53a47b22451dc3a73b29d72a2ce1405a4191f3c31ff927fea7b0514182f81ffc984364cc85499595eaefc509a06710c5277dcd22ebd7464917dfd9230'), 86 | data=None 87 | ), 88 | utxo.Output( 89 | value=40001 * COIN, 90 | destination=utxo.DestLockForStaking(dave_stash.public_key, dave.public_key,'0x0699553a3c5bfa89e41d94a45ceb9103ae9f87089b4a70de4c2a3eb922e1b9362fe0d8868ae4c9d5a9fba98d29b45d2c2630f4936077999f9334da1cca2e37e9'), 91 | data=None 92 | ), 93 | utxo.Output( 94 | value=39999919999 * COIN, 95 | destination=utxo.DestPubkey(charlie.public_key), 96 | data=None 97 | ) 98 | ] 99 | ).sign(alice, [utxos[0][1]]) 100 | client.submit(alice, tx1) 101 | 102 | # there should already be 4 accounts, adding Charlie and Dave in the list. 103 | assert_equal(len(list(client.staking_count())), 4) 104 | 105 | # Get Charlie 106 | charlie_count = list(client.get_staking_count(charlie_stash))[0][1] 107 | # charlie should have 1 locked utxos 108 | assert_equal(charlie_count[0], 1) 109 | # charlie should have a total of 50000 * COINS locked 110 | assert_equal(charlie_count[1], 40000 * COIN) 111 | 112 | # Get Dave 113 | dave_count = list(client.get_staking_count(dave_stash))[0][1] 114 | # dave should have 1 locked utxos 115 | assert_equal(dave_count[0], 1) 116 | # dave should have a total of 40001 * COINS locked 117 | assert_equal(dave_count[1], 40001 * COIN) 118 | 119 | # fetch the locked utxos from storage 120 | locked_utxos = list(client.utxos('LockedUtxos')) 121 | # there should already be 4 in the list; 1 from alice, 1 from bob, 1 from charlie, 1 from dave 122 | assert_equal(len(locked_utxos),4) 123 | 124 | # pallet-staking's ledger should have the same number of stakers 125 | assert_equal( len(list(client.get_staking_ledger())), 4) 126 | 127 | if __name__ == '__main__': 128 | ExampleTest().main() 129 | -------------------------------------------------------------------------------- /test/functional/feature_staking_extra.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2017 The Bitcoin Core developers 3 | # Distributed under the MIT software license, see the accompanying 4 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | """An example functional test 6 | 7 | Alice stakes an extra 40_000 utxo 8 | """ 9 | 10 | from substrateinterface import Keypair 11 | import test_framework.mintlayer.utxo as utxo 12 | 13 | from test_framework.test_framework import MintlayerTestFramework 14 | from test_framework.util import ( 15 | assert_equal, 16 | connect_nodes, 17 | wait_until, 18 | ) 19 | from test_framework.messages import COIN 20 | 21 | 22 | class ExampleTest(MintlayerTestFramework): 23 | # Each functional test is a subclass of the MintlayerTestFramework class. 24 | 25 | # Override the set_test_params(), add_options(), setup_chain(), setup_network() 26 | # and setup_nodes() methods to customize the test setup as required. 27 | 28 | def set_test_params(self): 29 | """Override test parameters for your individual test. 30 | 31 | This method must be overridden and num_nodes must be exlicitly set.""" 32 | self.setup_clean_chain = True 33 | self.num_nodes = 1 34 | # Use self.extra_args to change command-line arguments for the nodes 35 | self.extra_args = [[]] 36 | 37 | # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() 38 | 39 | def setup_network(self): 40 | """Setup the test network topology 41 | 42 | Often you won't need to override this, since the standard network topology 43 | (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests. 44 | 45 | If you do override this method, remember to start the nodes, assign 46 | them to self.nodes, connect them and then sync.""" 47 | 48 | self.setup_nodes() 49 | 50 | def custom_method(self): 51 | """Do some custom behaviour for this test 52 | 53 | Define it in a method here because you're going to use it repeatedly. 54 | If you think it's useful in general, consider moving it to the base 55 | MintlayerTestFramework class so other tests can use it.""" 56 | 57 | self.log.info("Running custom_method") 58 | 59 | def run_test(self): 60 | client = self.nodes[0].rpc_client 61 | 62 | alice = Keypair.create_from_uri('//Alice') 63 | alice_stash = Keypair.create_from_uri('//Alice//stash') 64 | 65 | # fetch the genesis utxo from storage 66 | utxos = list(client.utxos_for(alice_stash)) 67 | 68 | # Get Alice stash 69 | orig_count = list(client.get_staking_count(alice_stash))[0][1] 70 | # there should be 1 count of alice's locked utxo 71 | assert_equal(orig_count[0],1) 72 | # the amount that alice locked is 40_000 * MLT_UNIT 73 | assert_equal(orig_count[1],40000 * COIN) 74 | 75 | tx1 = utxo.Transaction( 76 | client, 77 | inputs=[ 78 | utxo.Input(utxos[0][0]), 79 | ], 80 | outputs=[ 81 | utxo.Output( 82 | value=40000 * COIN, 83 | destination=utxo.DestLockExtraForStaking(alice_stash.public_key, alice.public_key), 84 | data=None 85 | ), 86 | # This output prevent reward overflow 87 | utxo.Output( 88 | value=3981553255926290448385, # genesis amount - u64::MAX 89 | destination=utxo.DestPubkey(alice.public_key), 90 | data=None 91 | ) 92 | ] 93 | ).sign(alice_stash, [utxos[0][1]]) 94 | (_,_,events) = client.submit(alice_stash, tx1) 95 | 96 | assert_equal(events[0].value['module_id'],'Staking') 97 | assert_equal(events[0].value['event_id'], 'Bonded') 98 | 99 | assert_equal(events[1].value['module_id'],'Utxo') 100 | assert_equal(events[1].value['event_id'], 'TransactionSuccess') 101 | 102 | # Get Alice stash 103 | new_count = list(client.get_staking_count(alice_stash))[0][1] 104 | 105 | # there should already by 2 utxos locked 106 | assert_equal(new_count[0],2) 107 | 108 | # the original stake + new stake 109 | assert_equal(new_count[1],80000 * COIN) 110 | 111 | if __name__ == '__main__': 112 | ExampleTest().main() 113 | -------------------------------------------------------------------------------- /test/functional/feature_staking_extra_not_validator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2017 The Bitcoin Core developers 3 | # Distributed under the MIT software license, see the accompanying 4 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | """An example functional test 6 | 7 | Charlie tries to stake extra 40_000 utxo, even though it's his first time; 8 | and he's not actually a validator. 9 | """ 10 | 11 | from substrateinterface import Keypair 12 | import test_framework.mintlayer.utxo as utxo 13 | 14 | from test_framework.test_framework import MintlayerTestFramework 15 | from test_framework.util import ( 16 | assert_equal, 17 | connect_nodes, 18 | wait_until, 19 | ) 20 | from test_framework.messages import COIN 21 | 22 | 23 | class ExampleTest(MintlayerTestFramework): 24 | # Each functional test is a subclass of the MintlayerTestFramework class. 25 | 26 | # Override the set_test_params(), add_options(), setup_chain(), setup_network() 27 | # and setup_nodes() methods to customize the test setup as required. 28 | 29 | def set_test_params(self): 30 | """Override test parameters for your individual test. 31 | 32 | This method must be overridden and num_nodes must be exlicitly set.""" 33 | self.setup_clean_chain = True 34 | self.num_nodes = 1 35 | # Use self.extra_args to change command-line arguments for the nodes 36 | self.extra_args = [[]] 37 | 38 | # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() 39 | 40 | def setup_network(self): 41 | """Setup the test network topology 42 | 43 | Often you won't need to override this, since the standard network topology 44 | (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests. 45 | 46 | If you do override this method, remember to start the nodes, assign 47 | them to self.nodes, connect them and then sync.""" 48 | 49 | self.setup_nodes() 50 | 51 | def custom_method(self): 52 | """Do some custom behaviour for this test 53 | 54 | Define it in a method here because you're going to use it repeatedly. 55 | If you think it's useful in general, consider moving it to the base 56 | MintlayerTestFramework class so other tests can use it.""" 57 | 58 | self.log.info("Running custom_method") 59 | 60 | def run_test(self): 61 | client = self.nodes[0].rpc_client 62 | 63 | orig_count = list(client.staking_count()) 64 | # there should only be 1 count of each staker's locked utxo 65 | assert_equal(orig_count[0][1][0], 1) 66 | assert_equal(orig_count[1][1][0], 1) 67 | # the amount that alice/bob locked is 40_000 * MLT_UNIT 68 | assert_equal(orig_count[0][1][1], 40000 * COIN) 69 | # the amount that alice/bob locked is 40_000 * MLT_UNIT 70 | assert_equal(orig_count[1][1][1], 40000 * COIN) 71 | 72 | alice = Keypair.create_from_uri('//Alice') 73 | alice_stash = Keypair.create_from_uri('//Alice//stash') 74 | charlie = Keypair.create_from_uri('//Charlie') 75 | charlie_stash = Keypair.create_from_uri('//Charlie//stash') 76 | 77 | # fetch the genesis utxo from storage 78 | utxos = list(client.utxos_for(alice_stash)) 79 | 80 | tx1 = utxo.Transaction( 81 | client, 82 | inputs=[ 83 | utxo.Input(utxos[0][0]), 84 | ], 85 | outputs=[ 86 | utxo.Output( 87 | value=40000 * COIN, 88 | destination=utxo.DestLockExtraForStaking(charlie_stash.public_key, charlie.public_key), 89 | data=None 90 | ), 91 | ] 92 | ).sign(charlie_stash, [utxos[0][1]]) 93 | client.submit(charlie_stash, tx1) 94 | 95 | new_count = list(client.staking_count()) 96 | # there should only be 2 count of staking, which are Alice and Bob 97 | assert_equal(len(new_count), 2) 98 | 99 | if __name__ == '__main__': 100 | ExampleTest().main() 101 | -------------------------------------------------------------------------------- /test/functional/feature_staking_extra_wrong_controller.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2017 The Bitcoin Core developers 3 | # Distributed under the MIT software license, see the accompanying 4 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | """An example functional test 6 | 7 | Bob stakes an extra 40_000 utxo... but he inputted the wrong controller account 8 | """ 9 | 10 | from substrateinterface import Keypair 11 | import test_framework.mintlayer.utxo as utxo 12 | 13 | from test_framework.test_framework import MintlayerTestFramework 14 | from test_framework.util import ( 15 | assert_equal, 16 | connect_nodes, 17 | wait_until, 18 | ) 19 | from test_framework.messages import COIN 20 | 21 | 22 | class ExampleTest(MintlayerTestFramework): 23 | # Each functional test is a subclass of the MintlayerTestFramework class. 24 | 25 | # Override the set_test_params(), add_options(), setup_chain(), setup_network() 26 | # and setup_nodes() methods to customize the test setup as required. 27 | 28 | def set_test_params(self): 29 | """Override test parameters for your individual test. 30 | 31 | This method must be overridden and num_nodes must be exlicitly set.""" 32 | self.setup_clean_chain = True 33 | self.num_nodes = 2 34 | # Use self.extra_args to change command-line arguments for the nodes 35 | self.extra_args = [['--alice'],['--bob']] 36 | 37 | # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() 38 | 39 | def setup_network(self): 40 | """Setup the test network topology 41 | 42 | Often you won't need to override this, since the standard network topology 43 | (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests. 44 | 45 | If you do override this method, remember to start the nodes, assign 46 | them to self.nodes, connect them and then sync.""" 47 | 48 | self.setup_nodes() 49 | 50 | def custom_method(self): 51 | """Do some custom behaviour for this test 52 | 53 | Define it in a method here because you're going to use it repeatedly. 54 | If you think it's useful in general, consider moving it to the base 55 | MintlayerTestFramework class so other tests can use it.""" 56 | 57 | self.log.info("Running custom_method") 58 | 59 | def run_test(self): 60 | client = self.nodes[0].rpc_client 61 | 62 | bob = Keypair.create_from_uri('//Bob') 63 | alice_stash = Keypair.create_from_uri('//Alice//stash') 64 | 65 | # fetch the genesis utxo from storage 66 | utxos = list(client.utxos_for(alice_stash)) 67 | 68 | # Get Bob stash 69 | orig_count = list(client.get_staking_count(alice_stash))[0][1] 70 | # there should be 1 count of bob's locked utxo 71 | assert_equal(orig_count[0],1) 72 | # the amount that bob locked is 40_000 * MLT_UNIT 73 | assert_equal(orig_count[1],40000 * COIN) 74 | 75 | tx1 = utxo.Transaction( 76 | client, 77 | inputs=[ 78 | utxo.Input(utxos[0][0]), 79 | ], 80 | outputs=[ 81 | utxo.Output( 82 | value=40000 * COIN, 83 | destination=utxo.DestLockExtraForStaking(alice_stash.public_key, bob.public_key), 84 | data=None 85 | ), 86 | ] 87 | ).sign(alice_stash, [utxos[0][1]]) 88 | 89 | client.submit(alice_stash, tx1) 90 | 91 | # Get Bob's stash 92 | new_count = list(client.get_staking_count(alice_stash))[0][1] 93 | 94 | # there should still be only 1. 95 | assert_equal(new_count[0],1) 96 | 97 | # the stake stays the same 98 | assert_equal(new_count[1],40000 * COIN) 99 | 100 | if __name__ == '__main__': 101 | ExampleTest().main() 102 | -------------------------------------------------------------------------------- /test/functional/feature_staking_first_time.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2017 The Bitcoin Core developers 3 | # Distributed under the MIT software license, see the accompanying 4 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | """An example functional test 6 | 7 | Send a transaction from Alice to Charlie, then Charlie stakes for the first time. 8 | """ 9 | 10 | from substrateinterface import Keypair 11 | import test_framework.mintlayer.utxo as utxo 12 | 13 | from test_framework.test_framework import MintlayerTestFramework 14 | from test_framework.util import ( 15 | assert_equal, 16 | connect_nodes, 17 | wait_until, 18 | ) 19 | from test_framework.messages import COIN 20 | 21 | 22 | class ExampleTest(MintlayerTestFramework): 23 | # Each functional test is a subclass of the MintlayerTestFramework class. 24 | 25 | # Override the set_test_params(), add_options(), setup_chain(), setup_network() 26 | # and setup_nodes() methods to customize the test setup as required. 27 | 28 | def set_test_params(self): 29 | """Override test parameters for your individual test. 30 | 31 | This method must be overridden and num_nodes must be exlicitly set.""" 32 | self.setup_clean_chain = True 33 | self.num_nodes = 1 34 | # Use self.extra_args to change command-line arguments for the nodes 35 | self.extra_args = [[]] 36 | 37 | # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() 38 | 39 | def setup_network(self): 40 | """Setup the test network topology 41 | 42 | Often you won't need to override this, since the standard network topology 43 | (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests. 44 | 45 | If you do override this method, remember to start the nodes, assign 46 | them to self.nodes, connect them and then sync.""" 47 | 48 | self.setup_nodes() 49 | 50 | def custom_method(self): 51 | """Do some custom behaviour for this test 52 | 53 | Define it in a method here because you're going to use it repeatedly. 54 | If you think it's useful in general, consider moving it to the base 55 | MintlayerTestFramework class so other tests can use it.""" 56 | 57 | self.log.info("Running custom_method") 58 | 59 | def run_test(self): 60 | client = self.nodes[0].rpc_client 61 | 62 | alice = Keypair.create_from_uri('//Alice') 63 | charlie = Keypair.create_from_uri('//Charlie') 64 | charlie_stash = Keypair.create_from_uri('//Charlie//stash') 65 | 66 | # fetch the genesis utxo from storage 67 | utxos = list(client.utxos_for(alice)) 68 | 69 | # there's only 2 record of staking, which are alice and bob. 70 | assert_equal( len(list(client.staking_count())), 2 ) 71 | 72 | tx1 = utxo.Transaction( 73 | client, 74 | inputs=[ 75 | utxo.Input(utxos[0][0]), 76 | ], 77 | outputs=[ 78 | utxo.Output( 79 | value=50000 * COIN, 80 | destination=utxo.DestPubkey(charlie_stash.public_key), 81 | data=None 82 | ), 83 | utxo.Output( 84 | value=39999949950 * COIN, 85 | destination=utxo.DestPubkey(alice.public_key), 86 | data=None 87 | ), 88 | 89 | ] 90 | ).sign(alice, [utxos[0][1]]) 91 | client.submit(alice, tx1) 92 | 93 | tx2 = utxo.Transaction( 94 | client, 95 | inputs=[ 96 | utxo.Input(tx1.outpoint(0)), 97 | ], 98 | outputs=[ 99 | utxo.Output( 100 | value=40000 * COIN, 101 | destination=utxo.DestLockForStaking(charlie_stash.public_key, charlie.public_key,'0xa03bcfaac6ebdc26bb9c256c51b08f9c1c6d4569f48710a42939168d1d7e5b6086b20e145e97158f6a0b5bff2994439d3320543c8ff382d1ab3e5eafffaf1a18'), 102 | data=None 103 | ), 104 | utxo.Output( 105 | value=9999 * COIN, 106 | destination=utxo.DestPubkey(charlie_stash.public_key), 107 | data=None 108 | ), 109 | ] 110 | ).sign(charlie_stash, [tx1.outputs[0]]) 111 | client.submit(charlie_stash, tx2) 112 | 113 | # there should already be 3 staking, adding Charlie in the list. 114 | assert_equal( len(list(client.staking_count())), 3 ) 115 | 116 | # pallet-staking's ledger should have the same number of stakers 117 | assert_equal( len(list(client.get_staking_ledger())), 3) 118 | 119 | if __name__ == '__main__': 120 | ExampleTest().main() 121 | -------------------------------------------------------------------------------- /test/functional/feature_staking_less_than_minimum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2017 The Bitcoin Core developers 3 | # Distributed under the MIT software license, see the accompanying 4 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | """An example functional test 6 | 7 | Send a transaction from Alice to Charlie, but Charlie stakes less than the minimum required. 8 | """ 9 | 10 | from substrateinterface import Keypair 11 | import test_framework.mintlayer.utxo as utxo 12 | 13 | from test_framework.test_framework import MintlayerTestFramework 14 | from test_framework.util import ( 15 | assert_equal, 16 | connect_nodes, 17 | wait_until, 18 | ) 19 | from test_framework.messages import COIN 20 | 21 | 22 | class ExampleTest(MintlayerTestFramework): 23 | # Each functional test is a subclass of the MintlayerTestFramework class. 24 | 25 | # Override the set_test_params(), add_options(), setup_chain(), setup_network() 26 | # and setup_nodes() methods to customize the test setup as required. 27 | 28 | def set_test_params(self): 29 | """Override test parameters for your individual test. 30 | 31 | This method must be overridden and num_nodes must be exlicitly set.""" 32 | self.setup_clean_chain = True 33 | self.num_nodes = 1 34 | # Use self.extra_args to change command-line arguments for the nodes 35 | self.extra_args = [[]] 36 | 37 | # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() 38 | 39 | def setup_network(self): 40 | """Setup the test network topology 41 | 42 | Often you won't need to override this, since the standard network topology 43 | (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests. 44 | 45 | If you do override this method, remember to start the nodes, assign 46 | them to self.nodes, connect them and then sync.""" 47 | 48 | self.setup_nodes() 49 | 50 | def custom_method(self): 51 | """Do some custom behaviour for this test 52 | 53 | Define it in a method here because you're going to use it repeatedly. 54 | If you think it's useful in general, consider moving it to the base 55 | MintlayerTestFramework class so other tests can use it.""" 56 | 57 | self.log.info("Running custom_method") 58 | 59 | def run_test(self): 60 | client = self.nodes[0].rpc_client 61 | 62 | alice = Keypair.create_from_uri('//Alice') 63 | charlie = Keypair.create_from_uri('//Charlie') 64 | charlie_stash = Keypair.create_from_uri('//Charlie//stash') 65 | 66 | # fetch the genesis utxo from storage 67 | utxos = list(client.utxos_for(alice)) 68 | 69 | # there's only 2 record of staking, which are alice and bob. 70 | assert_equal( len(list(client.staking_count())), 2 ) 71 | 72 | tx1 = utxo.Transaction( 73 | client, 74 | inputs=[ 75 | utxo.Input(utxos[0][0]), 76 | ], 77 | outputs=[ 78 | utxo.Output( 79 | value=50000 * COIN, 80 | destination=utxo.DestPubkey(charlie_stash.public_key), 81 | data=None 82 | ), 83 | ] 84 | ).sign(alice, [utxos[0][1]]) 85 | client.submit(alice, tx1) 86 | 87 | tx2 = utxo.Transaction( 88 | client, 89 | inputs=[ 90 | utxo.Input(tx1.outpoint(0)), 91 | ], 92 | outputs=[ 93 | utxo.Output( 94 | value=4000 * COIN, 95 | destination=utxo.DestLockForStaking(charlie_stash.public_key, charlie.public_key,'0xa03bcfaac6ebdc26bb9c256c51b08f9c1c6d4569f48710a42939168d1d7e5b6086b20e145e97158f6a0b5bff2994439d3320543c8ff382d1ab3e5eafffaf1a18'), 96 | data=None 97 | ), 98 | utxo.Output( 99 | value=45999 * COIN, 100 | destination=utxo.DestPubkey(charlie_stash.public_key), 101 | data=None 102 | ), 103 | ] 104 | ).sign(charlie_stash, tx1.outputs) 105 | client.submit(charlie_stash, tx2) 106 | 107 | # there should only be 2 still, because Charlie failed on the staking. 108 | assert_equal(len(list(client.staking_count())), 2 ) 109 | 110 | if __name__ == '__main__': 111 | ExampleTest().main() 112 | -------------------------------------------------------------------------------- /test/functional/feature_staking_unlock_and_withdraw.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2017 The Bitcoin Core developers 3 | # Distributed under the MIT software license, see the accompanying 4 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | """An example functional test 6 | 7 | Alice wants to unlock her locked utxos, and withdraw; leaving Bob all alone. 8 | This was tested with Block time of 20 seconds. 9 | 10 | """ 11 | 12 | from substrateinterface import Keypair 13 | import test_framework.mintlayer.utxo as utxo 14 | import time 15 | from test_framework.test_framework import MintlayerTestFramework 16 | from test_framework.util import ( 17 | assert_equal, 18 | connect_nodes, 19 | wait_until, 20 | ) 21 | from test_framework.messages import COIN 22 | 23 | 24 | class ExampleTest(MintlayerTestFramework): 25 | # Each functional test is a subclass of the MintlayerTestFramework class. 26 | 27 | # Override the set_test_params(), add_options(), setup_chain(), setup_network() 28 | # and setup_nodes() methods to customize the test setup as required. 29 | 30 | def set_test_params(self): 31 | """Override test parameters for your individual test. 32 | 33 | This method must be overridden and num_nodes must be exlicitly set.""" 34 | self.setup_clean_chain = True 35 | self.num_nodes = 2 36 | # Use self.extra_args to change command-line arguments for the nodes 37 | self.extra_args = [['--alice'],['--bob']] 38 | # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() 39 | 40 | def setup_network(self): 41 | """Setup the test network topology 42 | 43 | Often you won't need to override this, since the standard network topology 44 | (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests. 45 | 46 | If you do override this method, remember to start the nodes, assign 47 | them to self.nodes, connect them and then sync.""" 48 | 49 | self.setup_nodes() 50 | connect_nodes(self.nodes[1], self.nodes[0]) 51 | 52 | def custom_method(self): 53 | """Do some custom behaviour for this test 54 | 55 | Define it in a method here because you're going to use it repeatedly. 56 | If you think it's useful in general, consider moving it to the base 57 | MintlayerTestFramework class so other tests can use it.""" 58 | 59 | self.log.info("Running custom_method") 60 | 61 | def run_test(self): 62 | client = self.nodes[0].rpc_client 63 | 64 | ledger = list(client.get_staking_ledger()) 65 | assert_equal(len(ledger[0][1]['unlocking']),0) 66 | 67 | alice_stash = Keypair.create_from_uri('//Alice//stash') 68 | 69 | # fetch the genesis utxo from storage 70 | utxos = list(client.utxos_for(alice_stash)) 71 | 72 | # Alice's locked utxo 73 | locked_utxos = list(map(lambda e: e[0].value, list(client.locked_utxos_for(alice_stash)))) 74 | 75 | # there's 2 records of staking, Alice's and Bob's. 76 | assert_equal( len(list(client.staking_count())), 2 ) 77 | 78 | (_, _, events) = client.unlock_request_for_withdrawal(alice_stash) 79 | 80 | assert_equal(events[0].value['module_id'],'Staking') 81 | assert_equal(events[0].value['event_id'], 'Chilled') 82 | 83 | assert_equal(events[1].value['module_id'],'Staking') 84 | assert_equal(events[1].value['event_id'], 'Unbonded') 85 | 86 | assert_equal(events[2].value['module_id'],'Utxo') 87 | assert_equal(events[2].value['event_id'], 'StakeUnlocked') 88 | 89 | ledger = list(client.get_staking_ledger()) 90 | assert_equal(len(ledger),2) 91 | 92 | time.sleep(500) 93 | 94 | (_, _, w_events) = client.withdraw_stake(alice_stash) 95 | 96 | 97 | assert_equal(w_events[0].value['module_id'],'Staking') 98 | assert_equal(w_events[0].value['event_id'], 'Withdrawn') 99 | 100 | assert_equal(w_events[1].value['module_id'],'Utxo') 101 | assert_equal(w_events[1].value['event_id'], 'StakeWithdrawn') 102 | 103 | assert_equal( len(list(client.staking_count())), 1) 104 | 105 | updated_ledger = list(client.get_staking_ledger()) 106 | assert_equal(len(updated_ledger),1) 107 | 108 | 109 | if __name__ == '__main__': 110 | ExampleTest().main() 111 | -------------------------------------------------------------------------------- /test/functional/feature_staking_unlock_not_validator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2017 The Bitcoin Core developers 3 | # Distributed under the MIT software license, see the accompanying 4 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | """An example functional test 6 | 7 | Charlie tries to "unlock" 8 | """ 9 | 10 | from substrateinterface import Keypair 11 | import test_framework.mintlayer.utxo as utxo 12 | 13 | from test_framework.test_framework import MintlayerTestFramework 14 | from test_framework.util import ( 15 | assert_equal, 16 | connect_nodes, 17 | wait_until, 18 | ) 19 | from test_framework.messages import COIN 20 | 21 | 22 | class ExampleTest(MintlayerTestFramework): 23 | # Each functional test is a subclass of the MintlayerTestFramework class. 24 | 25 | # Override the set_test_params(), add_options(), setup_chain(), setup_network() 26 | # and setup_nodes() methods to customize the test setup as required. 27 | 28 | def set_test_params(self): 29 | """Override test parameters for your individual test. 30 | 31 | This method must be overridden and num_nodes must be exlicitly set.""" 32 | self.setup_clean_chain = True 33 | self.num_nodes = 1 34 | # Use self.extra_args to change command-line arguments for the nodes 35 | self.extra_args = [[]] 36 | 37 | # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() 38 | 39 | def setup_network(self): 40 | """Setup the test network topology 41 | 42 | Often you won't need to override this, since the standard network topology 43 | (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests. 44 | 45 | If you do override this method, remember to start the nodes, assign 46 | them to self.nodes, connect them and then sync.""" 47 | 48 | self.setup_nodes() 49 | 50 | def custom_method(self): 51 | """Do some custom behaviour for this test 52 | 53 | Define it in a method here because you're going to use it repeatedly. 54 | If you think it's useful in general, consider moving it to the base 55 | MintlayerTestFramework class so other tests can use it.""" 56 | 57 | self.log.info("Running custom_method") 58 | 59 | def run_test(self): 60 | client = self.nodes[0].rpc_client 61 | 62 | ledger = list(client.get_staking_ledger()) 63 | assert_equal(len(ledger[0][1]['unlocking']),0) 64 | assert_equal(len(ledger[1][1]['unlocking']),0) 65 | 66 | charlie = Keypair.create_from_uri('//Charlie') 67 | 68 | client.unlock_request_for_withdrawal(charlie) 69 | 70 | ledger = list(client.get_staking_ledger()) 71 | assert_equal(len(ledger[0][1]['unlocking']),0) 72 | assert_equal(len(ledger[1][1]['unlocking']),0) 73 | 74 | locked_utxos = list(client.utxos('LockedUtxos')) 75 | # there should still be 2 utxos locked, no actual withdrawal happened. 76 | assert_equal(len(locked_utxos),2) 77 | 78 | if __name__ == '__main__': 79 | ExampleTest().main() 80 | -------------------------------------------------------------------------------- /test/functional/feature_staking_withdraw_no_unlock.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2017 The Bitcoin Core developers 3 | # Distributed under the MIT software license, see the accompanying 4 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | """An example functional test 6 | 7 | Alice wants to withdraw; forgetting to unlock first. 8 | 9 | """ 10 | 11 | from substrateinterface import Keypair 12 | import test_framework.mintlayer.utxo as utxo 13 | import time 14 | from test_framework.test_framework import MintlayerTestFramework 15 | from test_framework.util import ( 16 | assert_equal, 17 | connect_nodes, 18 | wait_until, 19 | ) 20 | from test_framework.messages import COIN 21 | 22 | 23 | class ExampleTest(MintlayerTestFramework): 24 | # Each functional test is a subclass of the MintlayerTestFramework class. 25 | 26 | # Override the set_test_params(), add_options(), setup_chain(), setup_network() 27 | # and setup_nodes() methods to customize the test setup as required. 28 | 29 | def set_test_params(self): 30 | """Override test parameters for your individual test. 31 | 32 | This method must be overridden and num_nodes must be exlicitly set.""" 33 | self.setup_clean_chain = True 34 | self.num_nodes = 2 35 | # Use self.extra_args to change command-line arguments for the nodes 36 | self.extra_args = [['--alice'],['--bob']] 37 | # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() 38 | 39 | def setup_network(self): 40 | """Setup the test network topology 41 | 42 | Often you won't need to override this, since the standard network topology 43 | (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests. 44 | 45 | If you do override this method, remember to start the nodes, assign 46 | them to self.nodes, connect them and then sync.""" 47 | 48 | self.setup_nodes() 49 | connect_nodes(self.nodes[1], self.nodes[0]) 50 | 51 | def custom_method(self): 52 | """Do some custom behaviour for this test 53 | 54 | Define it in a method here because you're going to use it repeatedly. 55 | If you think it's useful in general, consider moving it to the base 56 | MintlayerTestFramework class so other tests can use it.""" 57 | 58 | self.log.info("Running custom_method") 59 | 60 | def run_test(self): 61 | client = self.nodes[0].rpc_client 62 | 63 | ledger = list(client.get_staking_ledger()) 64 | assert_equal(len(ledger[0][1]['unlocking']),0) 65 | 66 | alice_stash = Keypair.create_from_uri('//Alice//stash') 67 | 68 | # Alice's locked utxo 69 | locked_utxos = list(map(lambda e: e[0].value, list(client.locked_utxos_for(alice_stash)))) 70 | 71 | # there's 2 records of staking, Alice's and Bob's. 72 | assert_equal( len(list(client.staking_count())), 2 ) 73 | 74 | ledger = list(client.get_staking_ledger()) 75 | assert_equal(len(ledger),2) 76 | 77 | client.withdraw_stake(alice_stash) 78 | 79 | assert_equal( len(list(client.staking_count())), 2) 80 | 81 | # no withdrawal happened 82 | updated_ledger = list(client.get_staking_ledger()) 83 | assert_equal(len(updated_ledger),2) 84 | 85 | 86 | if __name__ == '__main__': 87 | ExampleTest().main() 88 | -------------------------------------------------------------------------------- /test/functional/feature_staking_withdraw_not_validator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2017 The Bitcoin Core developers 3 | # Distributed under the MIT software license, see the accompanying 4 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 | """An example functional test 6 | 7 | Charlie tries to withdraw a stake which is not his. 8 | """ 9 | 10 | from substrateinterface import Keypair 11 | import test_framework.mintlayer.utxo as utxo 12 | 13 | from test_framework.test_framework import MintlayerTestFramework 14 | from test_framework.util import ( 15 | assert_equal, 16 | connect_nodes, 17 | wait_until, 18 | ) 19 | from test_framework.messages import COIN 20 | 21 | 22 | class ExampleTest(MintlayerTestFramework): 23 | # Each functional test is a subclass of the MintlayerTestFramework class. 24 | 25 | # Override the set_test_params(), add_options(), setup_chain(), setup_network() 26 | # and setup_nodes() methods to customize the test setup as required. 27 | 28 | def set_test_params(self): 29 | """Override test parameters for your individual test. 30 | 31 | This method must be overridden and num_nodes must be exlicitly set.""" 32 | self.setup_clean_chain = True 33 | self.num_nodes = 1 34 | # Use self.extra_args to change command-line arguments for the nodes 35 | self.extra_args = [[]] 36 | 37 | # self.log.info("I've finished set_test_params") # Oops! Can't run self.log before run_test() 38 | 39 | def setup_network(self): 40 | """Setup the test network topology 41 | 42 | Often you won't need to override this, since the standard network topology 43 | (linear: node0 <-> node1 <-> node2 <-> ...) is fine for most tests. 44 | 45 | If you do override this method, remember to start the nodes, assign 46 | them to self.nodes, connect them and then sync.""" 47 | 48 | self.setup_nodes() 49 | 50 | def custom_method(self): 51 | """Do some custom behaviour for this test 52 | 53 | Define it in a method here because you're going to use it repeatedly. 54 | If you think it's useful in general, consider moving it to the base 55 | MintlayerTestFramework class so other tests can use it.""" 56 | 57 | self.log.info("Running custom_method") 58 | 59 | def run_test(self): 60 | client = self.nodes[0].rpc_client 61 | 62 | ledger = list(client.get_staking_ledger()) 63 | assert_equal(len(ledger[0][1]['unlocking']),0) 64 | assert_equal(len(ledger[1][1]['unlocking']),0) 65 | 66 | charlie = Keypair.create_from_uri('//Charlie') 67 | client.withdraw_stake(charlie) 68 | 69 | ledger = list(client.get_staking_ledger()) 70 | assert_equal(len(ledger[0][1]['unlocking']),0) 71 | assert_equal(len(ledger[1][1]['unlocking']),0) 72 | 73 | locked_utxos = list(client.utxos('LockedUtxos')) 74 | # there should still be 2 utxo locked, no actual withdrawal happened. 75 | assert_equal(len(locked_utxos),2) 76 | 77 | #check that unlocking is successful, after an error happened 78 | alice_stash = Keypair.create_from_uri('//Alice//stash') 79 | (_, _, events) = client.unlock_request_for_withdrawal(alice_stash) 80 | 81 | assert_equal(events[0].value['module_id'],'Staking') 82 | assert_equal(events[0].value['event_id'], 'Chilled') 83 | 84 | assert_equal(events[1].value['module_id'],'Staking') 85 | assert_equal(events[1].value['event_id'], 'Unbonded') 86 | 87 | assert_equal(events[2].value['module_id'],'Utxo') 88 | assert_equal(events[2].value['event_id'], 'StakeUnlocked') 89 | 90 | 91 | 92 | 93 | if __name__ == '__main__': 94 | ExampleTest().main() 95 | -------------------------------------------------------------------------------- /test/functional/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadataVersion": "0.1.0", 3 | "source": { 4 | "hash": "0xd2d4276c5864e736fe51fd70c2e76ae600520dbead60bf3b8054f6d3d13e3dd7", 5 | "language": "ink! 3.0.0-rc4", 6 | "compiler": "rustc 1.56.0-nightly" 7 | }, 8 | "contract": { 9 | "name": "pooltest", 10 | "version": "0.1.0", 11 | "authors": [ 12 | "[your_name] <[your_email]>" 13 | ] 14 | }, 15 | "spec": { 16 | "constructors": [ 17 | { 18 | "args": [ 19 | { 20 | "name": "init_value", 21 | "type": { 22 | "displayName": [ 23 | "bool" 24 | ], 25 | "type": 1 26 | } 27 | } 28 | ], 29 | "docs": [ 30 | "Constructor that initializes the `bool` value to the given `init_value`." 31 | ], 32 | "name": [ 33 | "new" 34 | ], 35 | "selector": "0x9bae9d5e" 36 | }, 37 | { 38 | "args": [], 39 | "docs": [ 40 | "Constructor that initializes the `bool` value to `false`.", 41 | "", 42 | "Constructors can delegate to other constructors." 43 | ], 44 | "name": [ 45 | "default" 46 | ], 47 | "selector": "0xed4b9d1b" 48 | } 49 | ], 50 | "docs": [], 51 | "events": [], 52 | "messages": [ 53 | { 54 | "args": [], 55 | "docs": [ 56 | " A message that can be called on instantiated contracts.", 57 | " This one flips the value of the stored `bool` from `true`", 58 | " to `false` and vice versa." 59 | ], 60 | "mutates": true, 61 | "name": [ 62 | "flip" 63 | ], 64 | "payable": false, 65 | "returnType": null, 66 | "selector": "0x633aa551" 67 | }, 68 | { 69 | "args": [], 70 | "docs": [ 71 | " Simply returns the current value of our `bool`." 72 | ], 73 | "mutates": false, 74 | "name": [ 75 | "get" 76 | ], 77 | "payable": false, 78 | "returnType": { 79 | "displayName": [ 80 | "bool" 81 | ], 82 | "type": 1 83 | }, 84 | "selector": "0x2f865bd9" 85 | } 86 | ] 87 | }, 88 | "storage": { 89 | "struct": { 90 | "fields": [ 91 | { 92 | "layout": { 93 | "cell": { 94 | "key": "0x0000000000000000000000000000000000000000000000000000000000000000", 95 | "ty": 1 96 | } 97 | }, 98 | "name": "value" 99 | } 100 | ] 101 | } 102 | }, 103 | "types": [ 104 | { 105 | "def": { 106 | "primitive": "bool" 107 | } 108 | } 109 | ] 110 | } -------------------------------------------------------------------------------- /test/functional/test_framework/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | sys.path.insert(0, os.path.dirname(__file__)) 4 | 5 | import mintlayer 6 | -------------------------------------------------------------------------------- /test/functional/test_framework/address.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Copyright (c) 2021 RBB S.r.l 3 | # Copyright (c) 2016-2017 The Bitcoin Core developers 4 | # Distributed under the MIT software license, see the accompanying 5 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 6 | """Encode and decode BASE58, P2PKH and P2SH addresses.""" 7 | 8 | from script import hash256, hash160, sha256, CScript, OP_0 9 | from util import bytes_to_hex_str, hex_str_to_bytes 10 | 11 | # from . import segwit_addr 12 | 13 | ## --- Base58Check encoding 14 | __b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' 15 | __b58base = len(__b58chars) 16 | b58chars = __b58chars 17 | 18 | long = int 19 | _bchr = lambda x: bytes([x]) 20 | _bord = lambda x: x 21 | 22 | WIF_PREFIX = 0xb5 23 | TESTNET_WIF_PREFIX = 0xc1 24 | 25 | def byte_to_base58(b, version): 26 | result = '' 27 | str = bytes_to_hex_str(b) 28 | str = bytes_to_hex_str(chr(version).encode('latin-1')) + str 29 | checksum = bytes_to_hex_str(hash256(hex_str_to_bytes(str))) 30 | str += checksum[:8] 31 | value = int('0x'+str,0) 32 | while value > 0: 33 | result = __b58chars[value % 58] + result 34 | value //= 58 35 | while (str[:2] == '00'): 36 | result = __b58chars[0] + result 37 | str = str[2:] 38 | return result 39 | 40 | def b58encode(v): 41 | """ 42 | encode v, which is a string of bytes, to base58. 43 | """ 44 | long_value = 0 45 | for (i, c) in enumerate(v[::-1]): 46 | long_value += (256**i) * _bord(c) 47 | 48 | result = '' 49 | while long_value >= __b58base: 50 | div, mod = divmod(long_value, __b58base) 51 | result = __b58chars[mod] + result 52 | long_value = div 53 | result = __b58chars[long_value] + result 54 | # Bitcoin does a little leading-zero-compression: 55 | # leading 0-bytes in the input become leading-1s 56 | nPad = 0 57 | for c in v: 58 | # if c == '\0': nPad += 1 59 | if c == 0: 60 | nPad += 1 61 | else: 62 | break 63 | 64 | return (__b58chars[0] * nPad) + result 65 | 66 | def b58decode(v, length=None): 67 | """ decode v into a string of len bytes 68 | """ 69 | long_value = 0 70 | for (i, c) in enumerate(v[::-1]): 71 | long_value += __b58chars.find(c) * (__b58base**i) 72 | 73 | result = bytes() 74 | while long_value >= 256: 75 | div, mod = divmod(long_value, 256) 76 | result = _bchr(mod) + result 77 | long_value = div 78 | result = _bchr(long_value) + result 79 | 80 | nPad = 0 81 | for c in v: 82 | if c == __b58chars[0]: 83 | nPad += 1 84 | else: 85 | break 86 | 87 | result = _bchr(0) * nPad + result 88 | if length is not None and len(result) != length: 89 | return None 90 | 91 | return result 92 | 93 | def wif_to_privkey(secretString): 94 | wif_compressed = 52 == len(secretString) 95 | pvkeyencoded = b58decode(secretString).hex() 96 | wifversion = pvkeyencoded[:2] 97 | checksum = pvkeyencoded[-8:] 98 | vs = bytes.fromhex(pvkeyencoded[:-8]) 99 | check = hash256(vs)[0:4] 100 | 101 | if (wifversion == WIF_PREFIX.to_bytes(1, byteorder='big').hex() and checksum == check.hex()) \ 102 | or (wifversion == TESTNET_WIF_PREFIX.to_bytes(1, byteorder='big').hex() and checksum == check.hex()): 103 | 104 | if wif_compressed: 105 | privkey = pvkeyencoded[2:-10] 106 | 107 | else: 108 | privkey = pvkeyencoded[2:-8] 109 | 110 | return privkey, wif_compressed 111 | 112 | else: 113 | return None 114 | 115 | def keyhash_to_p2pkh(hash, main = False): 116 | assert (len(hash) == 20) 117 | version = 53 if main else 65 118 | return byte_to_base58(hash, version) 119 | 120 | def scripthash_to_p2sh(hash, main = False): 121 | assert (len(hash) == 20) 122 | version = 112 if main else 127 123 | return byte_to_base58(hash, version) 124 | 125 | def key_to_p2pkh(key, main = False): 126 | key = check_key(key) 127 | return keyhash_to_p2pkh(hash160(key), main) 128 | 129 | def script_to_p2sh(script, main = False): 130 | script = check_script(script) 131 | return scripthash_to_p2sh(hash160(script), main) 132 | 133 | def key_to_p2sh_p2wpkh(key, main = False): 134 | key = check_key(key) 135 | p2shscript = CScript([OP_0, hash160(key)]) 136 | return script_to_p2sh(p2shscript, main) 137 | 138 | # def program_to_witness(version, program, main = False): 139 | # if (type(program) is str): 140 | # program = hex_str_to_bytes(program) 141 | # assert 0 <= version <= 16 142 | # assert 2 <= len(program) <= 40 143 | # assert version > 0 or len(program) in [20, 32] 144 | # return segwit_addr.encode("bc" if main else "bcrt", version, program) 145 | 146 | # def script_to_p2wsh(script, main = False): 147 | # script = check_script(script) 148 | # return program_to_witness(0, sha256(script), main) 149 | # 150 | # def key_to_p2wpkh(key, main = False): 151 | # key = check_key(key) 152 | # return program_to_witness(0, hash160(key), main) 153 | 154 | def script_to_p2sh_p2wsh(script, main = False): 155 | script = check_script(script) 156 | p2shscript = CScript([OP_0, sha256(script)]) 157 | return script_to_p2sh(p2shscript, main) 158 | 159 | def check_key(key): 160 | if (type(key) is str): 161 | key = hex_str_to_bytes(key) # Assuming this is hex string 162 | if (type(key) is bytes and (len(key) == 33 or len(key) == 65)): 163 | return key 164 | assert(False) 165 | 166 | def check_script(script): 167 | if (type(script) is str): 168 | script = hex_str_to_bytes(script) # Assuming this is hex string 169 | if (type(script) is bytes or type(script) is CScript): 170 | return script 171 | assert(False) 172 | -------------------------------------------------------------------------------- /test/functional/test_framework/bignum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright (c) 2021 RBB S.r.l 4 | # Distributed under the MIT software license, see the accompanying 5 | # file COPYING or http://www.opensource.org/licenses/mit-license.php. 6 | """Big number routines. 7 | 8 | This file is copied from python-bitcoinlib. 9 | """ 10 | 11 | import struct 12 | 13 | 14 | # generic big endian MPI format 15 | 16 | def bn_bytes(v, have_ext=False): 17 | ext = 0 18 | if have_ext: 19 | ext = 1 20 | return ((v.bit_length()+7)//8) + ext 21 | 22 | def bn2bin(v): 23 | s = bytearray() 24 | i = bn_bytes(v) 25 | while i > 0: 26 | s.append((v >> ((i-1) * 8)) & 0xff) 27 | i -= 1 28 | return s 29 | 30 | def bn2mpi(v): 31 | have_ext = False 32 | if v.bit_length() > 0: 33 | have_ext = (v.bit_length() & 0x07) == 0 34 | 35 | neg = False 36 | if v < 0: 37 | neg = True 38 | v = -v 39 | 40 | s = struct.pack(b">I", bn_bytes(v, have_ext)) 41 | ext = bytearray() 42 | if have_ext: 43 | ext.append(0) 44 | v_bin = bn2bin(v) 45 | if neg: 46 | if have_ext: 47 | ext[0] |= 0x80 48 | else: 49 | v_bin[0] |= 0x80 50 | return s + ext + v_bin 51 | 52 | # bitcoin-specific little endian format, with implicit size 53 | def mpi2vch(s): 54 | r = s[4:] # strip size 55 | r = r[::-1] # reverse string, converting BE->LE 56 | return r 57 | 58 | def bn2vch(v): 59 | return bytes(mpi2vch(bn2mpi(v))) 60 | -------------------------------------------------------------------------------- /test/functional/test_framework/mintlayer/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | sys.path.insert(0, os.path.dirname(__file__)) 4 | 5 | import utxo -------------------------------------------------------------------------------- /test/functional/test_framework/mintlayer/_staking.py: -------------------------------------------------------------------------------- 1 | import substrateinterface 2 | 3 | 4 | class Staking(object): 5 | 6 | """ Query the node for the staking ledger """ 7 | def get_staking_ledger(self): 8 | query = self.substrate.query_map( 9 | module='Staking', 10 | storage_function='Ledger' 11 | ) 12 | 13 | return ((h, o.value) for (h, o) in query) 14 | -------------------------------------------------------------------------------- /test/functional/test_framework/mintlayer/contract.py: -------------------------------------------------------------------------------- 1 | #!/bin/python 2 | 3 | # Copyright (c) 2021 RBB S.r.l 4 | 5 | import substrateinterface 6 | from substrateinterface import SubstrateInterface, Keypair 7 | from substrateinterface.exceptions import SubstrateRequestException 8 | import scalecodec 9 | import json 10 | 11 | # fetch the contract account id from the block using its hash 12 | 13 | # TODO limitation here is that only one smart contract can be 14 | # created per block in order for this to work. 15 | # think of something a little more elegant 16 | def getContractAddresses(substrate, blk_hash): 17 | events = substrate.get_events(blk_hash) 18 | for event in events: 19 | if event.event_module.name == "System" and event.event.name == "NewAccount": 20 | return ( 21 | event.params[0]['value'], 22 | "0x" + substrateinterface.utils.ss58.ss58_decode(event.params[0]['value']) 23 | ) 24 | 25 | 26 | class ContractInstance(): 27 | def __init__(self, ss58, metadata, substrate): 28 | self.metadata = metadata 29 | self.substrate = substrate 30 | self.interface = substrateinterface.contracts.ContractInstance.create_from_address( 31 | contract_address = ss58, 32 | metadata_file = metadata, 33 | substrate = substrate 34 | ) 35 | 36 | def read(self, keypair, method): 37 | return self.interface.read(keypair, method) 38 | 39 | def generate_message_data(self, method, params): 40 | metadata = json.load(open(self.metadata)) 41 | ctr_tmp = substrateinterface.contracts.ContractMetadata(metadata, self.substrate) 42 | return ctr_tmp.generate_message_data(method, params) 43 | -------------------------------------------------------------------------------- /traits/pp-api/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pp-api" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ["RBB Lab"] 6 | description = "Programmable pool API for UTXO implemented by pallet-pp" 7 | license = "MIT" 8 | 9 | [dependencies.frame-support] 10 | default-features = false 11 | git = 'https://github.com/paritytech/substrate.git' 12 | version = '4.0.0-dev' 13 | branch = "master" 14 | 15 | [dependencies.sp-std] 16 | default-features = false 17 | git = 'https://github.com/paritytech/substrate.git' 18 | version = '4.0.0-dev' 19 | branch = "master" 20 | 21 | [dependencies.sp-core] 22 | default-features = false 23 | git = 'https://github.com/paritytech/substrate.git' 24 | version = '4.0.0-dev' 25 | branch = "master" 26 | 27 | [dependencies.sp-runtime] 28 | default-features = false 29 | git = 'https://github.com/paritytech/substrate.git' 30 | version = '4.0.0-dev' 31 | branch = "master" 32 | 33 | [dependencies.frame-system] 34 | default-features = false 35 | git = 'https://github.com/paritytech/substrate.git' 36 | version = '4.0.0-dev' 37 | branch = "master" 38 | 39 | [features] 40 | default = ['std'] 41 | std = [ 42 | 'frame-support/std', 43 | 'sp-std/std', 44 | ] 45 | -------------------------------------------------------------------------------- /traits/pp-api/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | use frame_support::{dispatch::Vec, weights::Weight}; 4 | use sp_core::H256; 5 | 6 | pub trait ProgrammablePoolApi { 7 | type AccountId; 8 | 9 | fn create( 10 | origin: &Self::AccountId, 11 | gas: Weight, 12 | code: &Vec, 13 | utxo_hash: H256, 14 | utxo_value: u128, 15 | data: &Vec, 16 | ) -> Result<(), &'static str>; 17 | 18 | fn call( 19 | caller: &Self::AccountId, 20 | dest: &Self::AccountId, 21 | gas_limit: Weight, 22 | utxo_hash: H256, 23 | utxo_value: u128, 24 | fund_contract: bool, 25 | input_data: &Vec, 26 | ) -> Result<(), &'static str>; 27 | } 28 | -------------------------------------------------------------------------------- /traits/utxo-api/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "utxo-api" 3 | version = "3.0.0" 4 | edition = "2018" 5 | authors = ["RBB Lab"] 6 | description = "UTXO API for programmable pools implemented by pallet-utxo" 7 | license = "MIT" 8 | 9 | [dependencies.frame-support] 10 | default-features = false 11 | git = 'https://github.com/paritytech/substrate.git' 12 | version = '4.0.0-dev' 13 | branch = "master" 14 | 15 | [dependencies.sp-std] 16 | default-features = false 17 | git = 'https://github.com/paritytech/substrate.git' 18 | version = '4.0.0-dev' 19 | branch = "master" 20 | 21 | [dependencies.sp-core] 22 | default-features = false 23 | git = 'https://github.com/paritytech/substrate.git' 24 | version = '4.0.0-dev' 25 | branch = "master" 26 | 27 | [dependencies.sp-runtime] 28 | default-features = false 29 | git = 'https://github.com/paritytech/substrate.git' 30 | version = '4.0.0-dev' 31 | branch = "master" 32 | 33 | [dependencies.frame-system] 34 | default-features = false 35 | git = 'https://github.com/paritytech/substrate.git' 36 | version = '4.0.0-dev' 37 | branch = "master" 38 | 39 | [features] 40 | default = ['std'] 41 | std = [ 42 | 'frame-support/std', 43 | 'sp-std/std', 44 | ] 45 | -------------------------------------------------------------------------------- /traits/utxo-api/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 RBB S.r.l 2 | // opensource@mintlayer.org 3 | // SPDX-License-Identifier: MIT 4 | // Licensed under the MIT License; 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://spdx.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | // Author(s): A. Altonen 17 | #![cfg_attr(not(feature = "std"), no_std)] 18 | 19 | use frame_support::{ 20 | dispatch::Vec, 21 | pallet_prelude::{DispatchError, DispatchResultWithPostInfo}, 22 | }; 23 | use sp_core::{H256, H512}; 24 | 25 | pub trait UtxoApi { 26 | type AccountId; 27 | 28 | fn spend( 29 | caller: &Self::AccountId, 30 | value: u128, 31 | address: H256, 32 | utxo: H256, 33 | sig: H512, 34 | ) -> DispatchResultWithPostInfo; 35 | 36 | fn unlock_request_for_withdrawal( 37 | stash_account_caller: &Self::AccountId, 38 | ) -> DispatchResultWithPostInfo; 39 | 40 | fn withdraw_stake(stash_account_caller: &Self::AccountId) -> DispatchResultWithPostInfo; 41 | 42 | fn send_conscrit_p2pk( 43 | caller: &Self::AccountId, 44 | destination: &Self::AccountId, 45 | value: u128, 46 | outpoints: &Vec, 47 | ) -> Result<(), DispatchError>; 48 | 49 | fn send_conscrit_c2c( 50 | caller: &Self::AccountId, 51 | destination: &Self::AccountId, 52 | value: u128, 53 | data: &Vec, 54 | outpoints: &Vec, 55 | ) -> Result<(), DispatchError>; 56 | } 57 | --------------------------------------------------------------------------------