Browse Source

Initial commit

Alex Siman 6 years ago
commit
411f6f59bd
21 changed files with 1012 additions and 0 deletions
  1. 16 0
      .editorconfig
  2. 12 0
      .gitignore
  3. 48 0
      Cargo.toml
  4. 24 0
      LICENSE
  5. 21 0
      README.md
  6. 31 0
      build.rs
  7. 26 0
      build.sh
  8. 1 0
      clean-chain.sh
  9. 1 0
      delete-chain-folder.sh
  10. 16 0
      init.sh
  11. 55 0
      runtime/Cargo.toml
  12. 304 0
      runtime/src/lib.rs
  13. 58 0
      runtime/wasm/Cargo.toml
  14. 13 0
      runtime/wasm/build.sh
  15. 1 0
      runtime/wasm/src
  16. 104 0
      src/chain_spec.rs
  17. 117 0
      src/cli.rs
  18. 13 0
      src/error.rs
  19. 46 0
      src/main.rs
  20. 104 0
      src/service.rs
  21. 1 0
      start-node.sh

+ 16 - 0
.editorconfig

@@ -0,0 +1,16 @@
+root = true
+[*]
+indent_style=tab
+indent_size=tab
+tab_width=4
+end_of_line=lf
+charset=utf-8
+trim_trailing_whitespace=true
+max_line_length=120
+insert_final_newline=true
+
+[*.yml]
+indent_style=space
+indent_size=2
+tab_width=8
+end_of_line=lf

+ 12 - 0
.gitignore

@@ -0,0 +1,12 @@
+# Generated by Cargo
+# will have compiled files and executables
+**/target/
+
+# Cargo lock in subs
+**/Cargo.lock
+
+# These are backup files generated by rustfmt
+**/*.rs.bk
+
+# JetBrains IDEs
+.idea

+ 48 - 0
Cargo.toml

@@ -0,0 +1,48 @@
+[package]
+name = "joystream-node"
+version = "0.9.0"
+authors = ["Parity Technologies <admin@parity.io>"]
+build = "build.rs"
+
+[[bin]]
+name = "joystream-node"
+path = "src/main.rs"
+
+[dependencies]
+error-chain = "0.12"
+futures = "0.1"
+ctrlc = { version = "3.0", features = ["termination"] }
+log = "0.4"
+tokio = "0.1.7"
+exit-future = "0.1"
+parking_lot = "0.4"
+hex-literal = "0.1"
+slog = "^2"
+parity-codec = { version = "2.1" }
+trie-root = { git = "https://github.com/paritytech/trie" }
+sr-io = { git = "https://github.com/paritytech/substrate" }
+sr-primitives = { git = "https://github.com/paritytech/substrate" }
+substrate-cli = { git = "https://github.com/paritytech/substrate" }
+substrate-primitives = { git = "https://github.com/paritytech/substrate" }
+substrate-executor = { git = "https://github.com/paritytech/substrate" }
+substrate-service = { git = "https://github.com/paritytech/substrate" }
+substrate-transaction-pool = { git = "https://github.com/paritytech/substrate" }
+substrate-network = { git = "https://github.com/paritytech/substrate" }
+substrate-consensus-aura = { git = "https://github.com/paritytech/substrate" }
+substrate-client = { git = "https://github.com/paritytech/substrate", default-features = false }
+substrate-finality-grandpa = { git = "https://github.com/paritytech/substrate" }
+substrate-basic-authorship = { git = "https://github.com/paritytech/substrate" }
+joystream-node-runtime = { path = "runtime" }
+node-executor = { git = "https://github.com/paritytech/substrate" }
+structopt = "0.2.13"
+
+[build-dependencies]
+vergen = "2"
+
+[workspace]
+members = [ "runtime" ]
+exclude = [ "runtime/wasm" ]
+
+[profile.release]
+# Substrate runtime requires unwinding.
+panic = "unwind"

+ 24 - 0
LICENSE

@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org>

+ 21 - 0
README.md

@@ -0,0 +1,21 @@
+# Joystream Substrate Node
+
+Joystream node built on top of Substrate.
+
+## Build
+
+```sh
+./build.sh
+```
+
+## Start node
+
+```sh
+./start-node.sh
+```
+
+## Clean chain data
+
+```sh
+./clean-chain.sh
+```

+ 31 - 0
build.rs

@@ -0,0 +1,31 @@
+// Copyright 2015-2018 Parity Technologies (UK) Ltd.
+// This file is part of Substrate.
+
+// Substrate is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Substrate is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Substrate.  If not, see <http://www.gnu.org/licenses/>.
+
+extern crate vergen;
+
+use vergen::{ConstantsFlags, Vergen};
+
+const ERROR_MSG: &'static str = "Failed to generate metadata files";
+
+fn main() {
+	let vergen = Vergen::new(ConstantsFlags::all()).expect(ERROR_MSG);
+
+	for (k, v) in vergen.build_info() {
+		println!("cargo:rustc-env={}={}", k.name(), v);
+	}
+
+	println!("cargo:rerun-if-changed=.git/HEAD");
+}

+ 26 - 0
build.sh

@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+set -e
+
+PROJECT_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
+
+export CARGO_INCREMENTAL=0
+
+bold=$(tput bold)
+normal=$(tput sgr0)
+
+# Save current directory.
+pushd . >/dev/null
+
+for SRC in runtime/wasm
+do
+  echo "${bold}Building webassembly binary in $SRC...${normal}"
+  cd "$PROJECT_ROOT/$SRC"
+
+  ./build.sh
+
+  cd - >> /dev/null
+done
+
+# Restore initial directory.
+popd >/dev/null

+ 1 - 0
clean-chain.sh

@@ -0,0 +1 @@
+cargo run -- --dev purge-chain

+ 1 - 0
delete-chain-folder.sh

@@ -0,0 +1 @@
+rm -rf ~/Library/Application\ Support/Substrate/chains/dev/

+ 16 - 0
init.sh

@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+set -e
+
+echo "*** Initialising WASM build environment"
+
+if [ -z $CI_PROJECT_NAME ] ; then
+   rustup update nightly
+   rustup update stable
+fi
+
+rustup target add wasm32-unknown-unknown --toolchain nightly
+
+# Install wasm-gc. It's useful for stripping slimming down wasm binaries.
+command -v wasm-gc || \
+	cargo +nightly install --git https://github.com/alexcrichton/wasm-gc --force

+ 55 - 0
runtime/Cargo.toml

@@ -0,0 +1,55 @@
+[package]
+name = "joystream-node-runtime"
+version = "0.9.0"
+authors = ["Parity Technologies <admin@parity.io>"]
+
+[dependencies]
+rustc-hex = "1.0"
+hex-literal = "0.1.0"
+serde = { version = "1.0", default-features = false }
+serde_derive = { version = "1.0", optional = true }
+safe-mix = { version = "1.0", default-features = false }
+parity-codec = "2.0"
+parity-codec-derive = "2.0"
+sr-std = { git = "https://github.com/paritytech/substrate" }
+sr-io = { git = "https://github.com/paritytech/substrate" }
+srml-support = { git = "https://github.com/paritytech/substrate" }
+substrate-primitives = { git = "https://github.com/paritytech/substrate" }
+substrate-keyring = { git = "https://github.com/paritytech/substrate" }
+srml-balances = { git = "https://github.com/paritytech/substrate" }
+srml-consensus = { git = "https://github.com/paritytech/substrate" }
+srml-aura = { git = "https://github.com/paritytech/substrate" }
+srml-executive = { git = "https://github.com/paritytech/substrate" }
+srml-indices = { git = "https://github.com/paritytech/substrate" }
+sr-primitives = { git = "https://github.com/paritytech/substrate" }
+srml-system = { git = "https://github.com/paritytech/substrate" }
+srml-timestamp = { git = "https://github.com/paritytech/substrate" }
+srml-sudo = { git = "https://github.com/paritytech/substrate" }
+substrate-client = { git = "https://github.com/paritytech/substrate", optional = true }
+sr-version = { git = "https://github.com/paritytech/substrate" }
+substrate-consensus-aura-primitives = { git = "https://github.com/paritytech/substrate" }
+
+[features]
+default = ["std"]
+std = [
+	"parity-codec/std",
+	"substrate-primitives/std",
+	"substrate-client/std",
+	"sr-std/std",
+	"sr-io/std",
+	"srml-support/std",
+	"srml-balances/std",
+	"srml-executive/std",
+	"srml-aura/std",
+	"srml-indices/std",
+	"sr-primitives/std",
+	"srml-system/std",
+	"srml-timestamp/std",
+	"srml-sudo/std",
+	"sr-version/std",
+	"serde_derive",
+	"serde/std",
+	"safe-mix/std",
+	"substrate-client",
+	"substrate-consensus-aura-primitives/std",
+]

+ 304 - 0
runtime/src/lib.rs

@@ -0,0 +1,304 @@
+//! The Substrate Node Template runtime. This can be compiled with `#[no_std]`, ready for Wasm.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+#![cfg_attr(not(feature = "std"), feature(alloc))]
+// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
+#![recursion_limit="256"]
+
+extern crate sr_std as rstd;
+extern crate sr_io as runtime_io;
+#[macro_use]
+extern crate substrate_client as client;
+#[macro_use]
+extern crate srml_support;
+#[macro_use]
+extern crate sr_primitives as runtime_primitives;
+#[cfg(feature = "std")]
+#[macro_use]
+extern crate serde_derive;
+extern crate substrate_primitives as primitives;
+extern crate parity_codec;
+#[macro_use]
+extern crate parity_codec_derive;
+#[macro_use]
+extern crate sr_version as version;
+extern crate srml_system as system;
+extern crate srml_executive as executive;
+extern crate srml_consensus as consensus;
+extern crate srml_timestamp as timestamp;
+extern crate srml_balances as balances;
+extern crate srml_sudo as sudo;
+extern crate srml_aura as aura;
+extern crate srml_indices as indices;
+extern crate substrate_consensus_aura_primitives as consensus_aura;
+
+use rstd::prelude::*;
+#[cfg(feature = "std")]
+use primitives::bytes;
+use primitives::{Ed25519AuthorityId, OpaqueMetadata};
+use runtime_primitives::{
+	ApplyResult, transaction_validity::TransactionValidity, Ed25519Signature, generic,
+	traits::{self, BlakeTwo256, Block as BlockT, ProvideInherent, StaticLookup},
+	BasicInherentData, CheckInherentError
+};
+use client::{block_builder::api as block_builder_api, runtime_api};
+use version::RuntimeVersion;
+#[cfg(feature = "std")]
+use version::NativeVersion;
+use consensus_aura::api as aura_api;
+
+// A few exports that help ease life for downstream crates.
+#[cfg(any(feature = "std", test))]
+pub use runtime_primitives::BuildStorage;
+pub use consensus::Call as ConsensusCall;
+pub use timestamp::Call as TimestampCall;
+pub use balances::Call as BalancesCall;
+pub use runtime_primitives::{Permill, Perbill};
+pub use timestamp::BlockPeriod;
+pub use srml_support::{StorageValue, RuntimeMetadata};
+
+/// Alias to Ed25519 pubkey that identifies an account on the chain.
+pub type AccountId = primitives::H256;
+
+/// A hash of some data used by the chain.
+pub type Hash = primitives::H256;
+
+/// Index of a block number in the chain.
+pub type BlockNumber = u64;
+
+/// Index of an account's extrinsic in the chain.
+pub type Nonce = u64;
+
+/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
+/// the specifics of the runtime. They can then be made to be agnostic over specific formats
+/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
+/// to even the core datastructures.
+pub mod opaque {
+	use super::*;
+
+	/// Opaque, encoded, unchecked extrinsic.
+	#[derive(PartialEq, Eq, Clone, Default, Encode, Decode)]
+	#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+	pub struct UncheckedExtrinsic(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
+	impl traits::Extrinsic for UncheckedExtrinsic {
+		fn is_signed(&self) -> Option<bool> {
+			None
+		}
+	}
+	/// Opaque block header type.
+	pub type Header = generic::Header<BlockNumber, BlakeTwo256, generic::DigestItem<Hash, Ed25519AuthorityId>>;
+	/// Opaque block type.
+	pub type Block = generic::Block<Header, UncheckedExtrinsic>;
+	/// Opaque block identifier type.
+	pub type BlockId = generic::BlockId<Block>;
+	/// Opaque session key type.
+	pub type SessionKey = Ed25519AuthorityId;
+}
+
+/// This runtime version.
+pub const VERSION: RuntimeVersion = RuntimeVersion {
+	spec_name: create_runtime_str!("joystream-node"),
+	impl_name: create_runtime_str!("joystream-node"),
+	authoring_version: 3,
+	spec_version: 3,
+	impl_version: 0,
+	apis: RUNTIME_API_VERSIONS,
+};
+
+/// The version infromation used to identify this runtime when compiled natively.
+#[cfg(feature = "std")]
+pub fn native_version() -> NativeVersion {
+	NativeVersion {
+		runtime_version: VERSION,
+		can_author_with: Default::default(),
+	}
+}
+
+impl system::Trait for Runtime {
+	/// The identifier used to distinguish between accounts.
+	type AccountId = AccountId;
+	/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
+	type Lookup = Indices;
+	/// The index type for storing how many extrinsics an account has signed.
+	type Index = Nonce;
+	/// The index type for blocks.
+	type BlockNumber = BlockNumber;
+	/// The type for hashing blocks and tries.
+	type Hash = Hash;
+	/// The hashing algorithm used.
+	type Hashing = BlakeTwo256;
+	/// The header digest type.
+	type Digest = generic::Digest<Log>;
+	/// The header type.
+	type Header = generic::Header<BlockNumber, BlakeTwo256, Log>;
+	/// The ubiquitous event type.
+	type Event = Event;
+	/// The ubiquitous log type.
+	type Log = Log;
+	/// The ubiquitous origin type.
+	type Origin = Origin;
+}
+
+impl aura::Trait for Runtime {
+	type HandleReport = ();
+}
+
+impl consensus::Trait for Runtime {
+	/// The position in the block's extrinsics that the note-offline inherent must be placed.
+	const NOTE_OFFLINE_POSITION: u32 = 1;
+	/// The identifier we use to refer to authorities.
+	type SessionKey = Ed25519AuthorityId;
+	// The aura module handles offline-reports internally
+	// rather than using an explicit report system.
+	type InherentOfflineReport = ();
+	/// The ubiquitous log type.
+	type Log = Log;
+}
+
+impl indices::Trait for Runtime {
+	/// The type for recording indexing into the account enumeration. If this ever overflows, there
+	/// will be problems!
+	type AccountIndex = u32;
+	/// Use the standard means of resolving an index hint from an id.
+	type ResolveHint = indices::SimpleResolveHint<Self::AccountId, Self::AccountIndex>;
+	/// Determine whether an account is dead.
+	type IsDeadAccount = Balances;
+	/// The uniquitous event type.
+	type Event = Event;
+}
+
+impl timestamp::Trait for Runtime {
+	/// The position in the block's extrinsics that the timestamp-set inherent must be placed.
+	const TIMESTAMP_SET_POSITION: u32 = 0;
+	/// A timestamp: seconds since the unix epoch.
+	type Moment = u64;
+	type OnTimestampSet = Aura;
+}
+
+impl balances::Trait for Runtime {
+	/// The type for recording an account's balance.
+	type Balance = u128;
+	/// What to do if an account's free balance gets zeroed.
+	type OnFreeBalanceZero = ();
+	/// What to do if a new account is created.
+	type OnNewAccount = Indices;
+	/// Restrict whether an account can transfer funds. We don't place any further restrictions.
+	type EnsureAccountLiquid = ();
+	/// The uniquitous event type.
+	type Event = Event;
+}
+
+impl sudo::Trait for Runtime {
+	/// The uniquitous event type.
+	type Event = Event;
+	type Proposal = Call;
+}
+
+construct_runtime!(
+	pub enum Runtime with Log(InternalLog: DigestItem<Hash, Ed25519AuthorityId>) where
+		Block = Block,
+		NodeBlock = opaque::Block,
+		InherentData = BasicInherentData
+	{
+		System: system::{default, Log(ChangesTrieRoot)},
+		Timestamp: timestamp::{Module, Call, Storage, Config<T>, Inherent},
+		Consensus: consensus::{Module, Call, Storage, Config<T>, Log(AuthoritiesChange), Inherent},
+		Aura: aura::{Module},
+		Indices: indices,
+		Balances: balances,
+		Sudo: sudo,
+	}
+);
+
+/// The type used as a helper for interpreting the sender of transactions.
+type Context = system::ChainContext<Runtime>;
+/// The address format for describing accounts.
+type Address = <Indices as StaticLookup>::Source;
+/// Block header type as expected by this runtime.
+pub type Header = generic::Header<BlockNumber, BlakeTwo256, Log>;
+/// Block type as expected by this runtime.
+pub type Block = generic::Block<Header, UncheckedExtrinsic>;
+/// BlockId type as expected by this runtime.
+pub type BlockId = generic::BlockId<Block>;
+/// Unchecked extrinsic type as expected by this runtime.
+pub type UncheckedExtrinsic = generic::UncheckedMortalCompactExtrinsic<Address, Nonce, Call, Ed25519Signature>;
+/// Extrinsic type that has already been checked.
+pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Nonce, Call>;
+/// Executive: handles dispatch to the various modules.
+pub type Executive = executive::Executive<Runtime, Block, Context, Balances, AllModules>;
+
+// Implement our runtime API endpoints. This is just a bunch of proxying.
+impl_runtime_apis! {
+	impl runtime_api::Core<Block> for Runtime {
+		fn version() -> RuntimeVersion {
+			VERSION
+		}
+
+		fn authorities() -> Vec<Ed25519AuthorityId> {
+			Consensus::authorities()
+		}
+
+		fn execute_block(block: Block) {
+			Executive::execute_block(block)
+		}
+
+		fn initialise_block(header: <Block as BlockT>::Header) {
+			Executive::initialise_block(&header)
+		}
+	}
+
+	impl runtime_api::Metadata<Block> for Runtime {
+		fn metadata() -> OpaqueMetadata {
+			Runtime::metadata().into()
+		}
+	}
+
+	impl block_builder_api::BlockBuilder<Block, BasicInherentData> for Runtime {
+		fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyResult {
+			Executive::apply_extrinsic(extrinsic)
+		}
+
+		fn finalise_block() -> <Block as BlockT>::Header {
+			Executive::finalise_block()
+		}
+
+		fn inherent_extrinsics(data: BasicInherentData) -> Vec<<Block as BlockT>::Extrinsic> {
+			let mut inherent = Vec::new();
+
+			inherent.extend(
+				Timestamp::create_inherent_extrinsics(data.timestamp)
+					.into_iter()
+					.map(|v| (v.0, UncheckedExtrinsic::new_unsigned(Call::Timestamp(v.1))))
+			);
+
+			inherent.extend(
+				Consensus::create_inherent_extrinsics(data.consensus)
+					.into_iter()
+					.map(|v| (v.0, UncheckedExtrinsic::new_unsigned(Call::Consensus(v.1))))
+			);
+
+			inherent.as_mut_slice().sort_unstable_by_key(|v| v.0);
+			inherent.into_iter().map(|v| v.1).collect()
+		}
+
+		fn check_inherents(block: Block, data: BasicInherentData) -> Result<(), CheckInherentError> {
+			Runtime::check_inherents(block, data)
+		}
+
+		fn random_seed() -> <Block as BlockT>::Hash {
+			System::random_seed()
+		}
+	}
+
+	impl runtime_api::TaggedTransactionQueue<Block> for Runtime {
+		fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
+			Executive::validate_transaction(tx)
+		}
+	}
+
+	impl aura_api::AuraApi<Block> for Runtime {
+		fn slot_duration() -> u64 {
+			Aura::slot_duration()
+		}
+	}
+}

+ 58 - 0
runtime/wasm/Cargo.toml

@@ -0,0 +1,58 @@
+[package]
+name = "joystream-node-runtime"
+version = "0.9.0"
+authors = ["Parity Technologies <admin@parity.io>"]
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+integer-sqrt = { git = "https://github.com/paritytech/integer-sqrt-rs.git" }
+safe-mix = { version = "1.0", default-features = false}
+parity-codec-derive = { version = "^2.1" }
+parity-codec = { version = "^2.1", default-features = false }
+substrate-primitives = { git = "https://github.com/paritytech/substrate", default-features = false }
+substrate-client = { git = "https://github.com/paritytech/substrate", default-features = false }
+sr-std = { git = "https://github.com/paritytech/substrate", default-features = false }
+sr-io = { git = "https://github.com/paritytech/substrate", default-features = false }
+srml-support = { git = "https://github.com/paritytech/substrate", default-features = false }
+srml-balances = { git = "https://github.com/paritytech/substrate", default-features = false }
+srml-consensus = { git = "https://github.com/paritytech/substrate", default-features = false }
+srml-executive = { git = "https://github.com/paritytech/substrate", default-features = false }
+srml-aura = { git = "https://github.com/paritytech/substrate", default-features = false }
+sr-primitives = { git = "https://github.com/paritytech/substrate", default-features = false }
+srml-system = { git = "https://github.com/paritytech/substrate", default-features = false }
+srml-indices = { git = "https://github.com/paritytech/substrate", default-features = false }
+srml-timestamp = { git = "https://github.com/paritytech/substrate", default-features = false }
+srml-sudo = { git = "https://github.com/paritytech/substrate", default-features = false }
+sr-version = { git = "https://github.com/paritytech/substrate", default-features = false }
+substrate-consensus-aura-primitives = { git = "https://github.com/paritytech/substrate", default-features = false }
+
+[features]
+default = []
+std = [
+	"safe-mix/std",
+	"parity-codec/std",
+	"substrate-primitives/std",
+	"substrate-client/std",
+	"sr-std/std",
+	"sr-io/std",
+	"srml-support/std",
+	"srml-balances/std",
+	"srml-consensus/std",
+	"srml-executive/std",
+	"srml-aura/std",
+	"sr-primitives/std",
+	"srml-indices/std",
+	"srml-system/std",
+	"srml-timestamp/std",
+	"srml-sudo/std",
+	"sr-version/std",
+]
+
+[profile.release]
+panic = "abort"
+lto = true
+
+[workspace]
+members = []

+ 13 - 0
runtime/wasm/build.sh

@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+set -e
+
+if cargo --version | grep -q "nightly"; then
+	CARGO_CMD="cargo"
+else
+	CARGO_CMD="cargo +nightly"
+fi
+$CARGO_CMD build --target=wasm32-unknown-unknown --release
+for i in joystream_node_runtime
+do
+	wasm-gc target/wasm32-unknown-unknown/release/$i.wasm target/wasm32-unknown-unknown/release/$i.compact.wasm
+done

+ 1 - 0
runtime/wasm/src

@@ -0,0 +1 @@
+../src

+ 104 - 0
src/chain_spec.rs

@@ -0,0 +1,104 @@
+use primitives::{Ed25519AuthorityId, ed25519};
+use joystream_node_runtime::{
+	AccountId, GenesisConfig, ConsensusConfig, TimestampConfig, BalancesConfig,
+	SudoConfig, IndicesConfig
+};
+use substrate_service;
+
+// Note this is the URL for the telemetry server
+//const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
+
+/// Specialised `ChainSpec`. This is a specialisation of the general Substrate ChainSpec type.
+pub type ChainSpec = substrate_service::ChainSpec<GenesisConfig>;
+
+/// The chain specification option. This is expected to come in from the CLI and
+/// is little more than one of a number of alternatives which can easily be converted
+/// from a string (`--chain=...`) into a `ChainSpec`.
+#[derive(Clone, Debug)]
+pub enum Alternative {
+	/// Whatever the current runtime is, with just Alice as an auth.
+	Development,
+	/// Whatever the current runtime is, with simple Alice/Bob auths.
+	LocalTestnet,
+}
+
+impl Alternative {
+	/// Get an actual chain config from one of the alternatives.
+	pub(crate) fn load(self) -> Result<ChainSpec, String> {
+		Ok(match self {
+			Alternative::Development => ChainSpec::from_genesis(
+				"Development",
+				"dev",
+				|| testnet_genesis(vec![
+					ed25519::Pair::from_seed(b"Alice                           ").public().into(),
+				], vec![
+					ed25519::Pair::from_seed(b"Alice                           ").public().0.into(),
+				],
+					ed25519::Pair::from_seed(b"Alice                           ").public().0.into()
+				),
+				vec![],
+				None,
+				None,
+				None,
+				None
+			),
+			Alternative::LocalTestnet => ChainSpec::from_genesis(
+				"Local Testnet",
+				"local_testnet",
+				|| testnet_genesis(vec![
+					ed25519::Pair::from_seed(b"Alice                           ").public().into(),
+					ed25519::Pair::from_seed(b"Bob                             ").public().into(),
+				], vec![
+					ed25519::Pair::from_seed(b"Alice                           ").public().0.into(),
+					ed25519::Pair::from_seed(b"Bob                             ").public().0.into(),
+					ed25519::Pair::from_seed(b"Charlie                         ").public().0.into(),
+					ed25519::Pair::from_seed(b"Dave                            ").public().0.into(),
+					ed25519::Pair::from_seed(b"Eve                             ").public().0.into(),
+					ed25519::Pair::from_seed(b"Ferdie                          ").public().0.into(),
+				],
+					ed25519::Pair::from_seed(b"Alice                           ").public().0.into()
+				),
+				vec![],
+				None,
+				None,
+				None,
+				None
+			),
+		})
+	}
+
+	pub(crate) fn from(s: &str) -> Option<Self> {
+		match s {
+			"dev" => Some(Alternative::Development),
+			"local" => Some(Alternative::LocalTestnet),
+			_ => None,
+		}
+	}
+}
+
+fn testnet_genesis(initial_authorities: Vec<Ed25519AuthorityId>, endowed_accounts: Vec<AccountId>, root_key: AccountId) -> GenesisConfig {
+	GenesisConfig {
+		consensus: Some(ConsensusConfig {
+			code: include_bytes!("../runtime/wasm/target/wasm32-unknown-unknown/release/joystream_node_runtime.compact.wasm").to_vec(),
+			authorities: initial_authorities.clone(),
+		}),
+		system: None,
+		timestamp: Some(TimestampConfig {
+			period: 5,					// 5 second block time.
+		}),
+		indices: Some(IndicesConfig {
+			ids: endowed_accounts.clone(),
+		}),
+		balances: Some(BalancesConfig {
+			transaction_base_fee: 1,
+			transaction_byte_fee: 0,
+			existential_deposit: 500,
+			transfer_fee: 0,
+			creation_fee: 0,
+			balances: endowed_accounts.iter().map(|&k|(k, (1 << 60))).collect(),
+		}),
+		sudo: Some(SudoConfig {
+			key: root_key,
+		}),
+	}
+}

+ 117 - 0
src/cli.rs

@@ -0,0 +1,117 @@
+use service;
+use futures::{future, Future, sync::oneshot};
+use std::cell::RefCell;
+use tokio::runtime::Runtime;
+pub use substrate_cli::{VersionInfo, IntoExit, error};
+use substrate_cli::{Action, informant, parse_matches, execute_default, CoreParams};
+use substrate_service::{ServiceFactory, Roles as ServiceRoles};
+use chain_spec;
+use std::ops::Deref;
+use structopt::StructOpt;
+
+/// Extend params for Node
+#[derive(Debug, StructOpt)]
+pub struct NodeParams {
+	/// Should run as a GRANDPA authority node
+	#[structopt(long = "grandpa-authority", help = "Run Node as a GRANDPA authority, implies --validator")]
+	grandpa_authority: bool,
+
+	/// Should run as a GRANDPA authority node only
+	#[structopt(long = "grandpa-authority-only", help = "Run Node as a GRANDPA authority only, don't as a usual validator, implies --grandpa-authority")]
+	grandpa_authority_only: bool,
+
+	#[structopt(flatten)]
+	core: CoreParams
+}
+
+/// Parse command line arguments into service configuration.
+pub fn run<I, T, E>(args: I, exit: E, version: VersionInfo) -> error::Result<()> where
+	I: IntoIterator<Item = T>,
+	T: Into<std::ffi::OsString> + Clone,
+	E: IntoExit,
+{
+	let full_version = substrate_service::config::full_version_from_strs(
+		version.version,
+		version.commit
+	);
+
+	let matches = match NodeParams::clap()
+		.name(version.executable_name)
+		.author(version.author)
+		.about(version.description)
+		.version(&(full_version + "\n")[..])
+		.get_matches_from_safe(args) {
+			Ok(m) => m,
+			Err(e) => e.exit(),
+		};
+
+	let (spec, config) = parse_matches::<service::Factory, _>(
+		load_spec, version, "substrate-node", &matches
+	)?;
+
+	match execute_default::<service::Factory, _>(spec, exit, &matches, &config)? {
+		Action::ExecutedInternally => (),
+		Action::RunService(exit) => {
+			info!("Substrate Node");
+			info!("  version {}", config.full_version());
+			info!("  by Parity Technologies, 2017, 2018");
+			info!("Chain specification: {}", config.chain_spec.name());
+			info!("Node name: {}", config.name);
+			info!("Roles: {:?}", config.roles);
+			let mut runtime = Runtime::new()?;
+			let executor = runtime.executor();
+			match config.roles == ServiceRoles::LIGHT {
+				true => run_until_exit(&mut runtime, service::Factory::new_light(config, executor)?, exit)?,
+				false => run_until_exit(&mut runtime, service::Factory::new_full(config, executor)?, exit)?,
+			}
+		}
+	}
+
+	Ok(())
+}
+
+fn load_spec(id: &str) -> Result<Option<chain_spec::ChainSpec>, String> {
+	Ok(match chain_spec::Alternative::from(id) {
+		Some(spec) => Some(spec.load()?),
+		None => None,
+	})
+}
+
+fn run_until_exit<T, C, E>(
+	runtime: &mut Runtime,
+	service: T,
+	e: E,
+) -> error::Result<()>
+	where
+		T: Deref<Target=substrate_service::Service<C>>,
+		C: substrate_service::Components,
+		E: IntoExit,
+{
+	let (exit_send, exit) = exit_future::signal();
+
+	let executor = runtime.executor();
+	informant::start(&service, exit.clone(), executor.clone());
+
+	let _ = runtime.block_on(e.into_exit());
+	exit_send.fire();
+	Ok(())
+}
+
+// handles ctrl-c
+pub struct Exit;
+impl IntoExit for Exit {
+	type Exit = future::MapErr<oneshot::Receiver<()>, fn(oneshot::Canceled) -> ()>;
+	fn into_exit(self) -> Self::Exit {
+		// can't use signal directly here because CtrlC takes only `Fn`.
+		let (exit_send, exit) = oneshot::channel();
+
+		let exit_send_cell = RefCell::new(Some(exit_send));
+		ctrlc::set_handler(move || {
+			if let Some(exit_send) = exit_send_cell.try_borrow_mut().expect("signal handler not reentrant; qed").take() {
+				exit_send.send(()).expect("Error sending exit notification");
+			}
+		}).expect("Error setting Ctrl-C handler");
+
+		exit.map_err(drop)
+	}
+}

+ 13 - 0
src/error.rs

@@ -0,0 +1,13 @@
+//! Initialization errors.
+
+use client;
+
+error_chain! {
+	foreign_links {
+		Io(::std::io::Error) #[doc="IO error"];
+		Cli(::clap::Error) #[doc="CLI error"];
+	}
+	links {
+		Client(client::error::Error, client::error::ErrorKind) #[doc="Client error"];
+	}
+}

+ 46 - 0
src/main.rs

@@ -0,0 +1,46 @@
+//! Substrate Node Template CLI library.
+
+#![warn(missing_docs)]
+#![warn(unused_extern_crates)]
+
+extern crate futures;
+#[macro_use]
+extern crate error_chain;
+extern crate tokio;
+#[macro_use]
+extern crate log;
+extern crate substrate_cli;
+extern crate substrate_primitives as primitives;
+extern crate substrate_consensus_aura as consensus;
+extern crate substrate_client as client;
+#[macro_use]
+extern crate substrate_network as network;
+#[macro_use]
+extern crate substrate_executor;
+extern crate substrate_transaction_pool as transaction_pool;
+extern crate substrate_basic_authorship as basic_authorship;
+#[macro_use]
+extern crate substrate_service;
+extern crate joystream_node_runtime;
+extern crate structopt;
+extern crate node_executor;
+extern crate sr_primitives as runtime_primitives;
+
+mod chain_spec;
+mod service;
+mod cli;
+
+pub use substrate_cli::{VersionInfo, IntoExit, error};
+
+fn run() -> cli::error::Result<()> {
+	let version = VersionInfo {
+		commit: env!("VERGEN_SHA_SHORT"),
+		version: env!("CARGO_PKG_VERSION"),
+		executable_name: "joystream-node",
+		author: "jsgenesis",
+		description: "joystream-node",
+	};
+	cli::run(::std::env::args(), cli::Exit, version)
+}
+
+quick_main!(run);

+ 104 - 0
src/service.rs

@@ -0,0 +1,104 @@
+//! Service and ServiceFactory implementation. Specialized wrapper over Substrate service.
+
+#![warn(unused_extern_crates)]
+
+use std::sync::Arc;
+use transaction_pool::{self, txpool::{Pool as TransactionPool}};
+use joystream_node_runtime::{self, GenesisConfig, opaque::Block, RuntimeApi};
+use substrate_service::{
+	FactoryFullConfiguration, LightComponents, FullComponents, FullBackend,
+	FullClient, LightClient, LightBackend, FullExecutor, LightExecutor,
+	TaskExecutor,
+};
+use basic_authorship::ProposerFactory;
+use node_executor;
+use consensus::{import_queue, start_aura, AuraImportQueue, SlotDuration, NothingExtra};
+use client;
+use primitives::ed25519::Pair;
+use runtime_primitives::BasicInherentData as InherentData;
+
+pub use substrate_executor::NativeExecutor;
+// Our native executor instance.
+native_executor_instance!(
+	pub Executor,
+	joystream_node_runtime::api::dispatch,
+	joystream_node_runtime::native_version,
+	include_bytes!("../runtime/wasm/target/wasm32-unknown-unknown/release/joystream_node_runtime.compact.wasm")
+);
+
+construct_simple_protocol! {
+	/// Demo protocol attachment for substrate.
+	pub struct NodeProtocol where Block = Block { }
+}
+
+construct_service_factory! {
+	struct Factory {
+		Block = Block,
+		RuntimeApi = RuntimeApi,
+		NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) },
+		RuntimeDispatch = node_executor::Executor,
+		FullTransactionPoolApi = transaction_pool::ChainApi<client::Client<FullBackend<Self>, FullExecutor<Self>, Block, RuntimeApi>, Block>
+			{ |config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client))) },
+		LightTransactionPoolApi = transaction_pool::ChainApi<client::Client<LightBackend<Self>, LightExecutor<Self>, Block, RuntimeApi>, Block>
+			{ |config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client))) },
+		Genesis = GenesisConfig,
+		Configuration = (),
+		FullService = FullComponents<Self>
+			{ |config: FactoryFullConfiguration<Self>, executor: TaskExecutor|
+				FullComponents::<Factory>::new(config, executor)
+			},
+		AuthoritySetup = {
+			|service: Self::FullService, executor: TaskExecutor, key: Option<Arc<Pair>>| {
+				if let Some(key) = key {
+					info!("Using authority key {}", key.public());
+					let proposer = Arc::new(ProposerFactory {
+						client: service.client(),
+						transaction_pool: service.transaction_pool(),
+					});
+					let client = service.client();
+					executor.spawn(start_aura(
+						SlotDuration::get_or_compute(&*client)?,
+						key.clone(),
+						client.clone(),
+						client,
+						proposer,
+						service.network(),
+						service.on_exit(),
+					));
+				}
+
+				Ok(service)
+			}
+		},
+		LightService = LightComponents<Self>
+			{ |config, executor| <LightComponents<Factory>>::new(config, executor) },
+		FullImportQueue = AuraImportQueue<
+			Self::Block,
+			FullClient<Self>,
+			NothingExtra,
+			::consensus::InherentProducingFn<InherentData>,
+		>
+			{ |config: &mut FactoryFullConfiguration<Self> , client: Arc<FullClient<Self>>|
+				Ok(import_queue(
+					SlotDuration::get_or_compute(&*client)?,
+					client,
+					NothingExtra,
+					::consensus::make_basic_inherent as _,
+				))
+			},
+		LightImportQueue = AuraImportQueue<
+			Self::Block,
+			LightClient<Self>,
+			NothingExtra,
+			::consensus::InherentProducingFn<InherentData>,
+		>
+			{ |ref mut config, client: Arc<LightClient<Self>>|
+				Ok(import_queue(
+					SlotDuration::get_or_compute(&*client)?,
+					client,
+					NothingExtra,
+					::consensus::make_basic_inherent as _,
+				))
+			},
+	}
+}

+ 1 - 0
start-node.sh

@@ -0,0 +1 @@
+./target/release/joystream-node --dev