Substrate
ブロックチェーン構築ライブラリかつ、substrateベースチェーンへの同期クライアントを作るフレームワーク
動的かつ自己決定的な状態遷移関数
ライトクライアント
fast block profuctionなconsensus algorithm, definite finarilty.
Header := Parent + ExtrinsicsRoot + StorageRoot + Digest
Block := Header + Extrinsics + Justifications
Extrinsics
transactions
signed and gossipped on the network
inherents
not passed on the network and not signed
describes environment which are assumed to be true because a sufficiently large number of validators have agreed on them being reasonable.
例えばtimestamp
code: api.rs
pub mod api {
impl_stubs!(
// Standard: Required.
version => |()| super::Version::version(),
authorities => |()| super::Consensus::authorities(),
execute_block => |block| super::Executive::execute_block(block),
// Conventional: Needed for Substrate client's reference block authoring logic to work.
initialise_block => |header| super::Executive::initialise_block(&header),
apply_extrinsic => |extrinsic| super::Executive::apply_extrinsic(extrinsic),
finalise_block => |()| super::Executive::finalise_block(),
inherent_extrinsics => |inherent| super::inherent_extrinsics(inherent),
// Non-standard (Polkadot-specific). This just exposes some stuff that Polkadot client
// finds useful.
validator_count => |()| super::Session::validator_count(),
validators => |()| super::Session::validators()
);
}
substrate core
network blockchain node
substrate runtime module library (SRML)
chain-specific implementations
consensus
asset, account, balance
polkadot vs cosmos
A Tale of Two Technologies Presentation Transcript
Address, Account Index and Account ID in Extrinsic
アカウントの識別
32 byte AccountId is alias to Ed25519 pubkey
64bit AccountIndex => AccountId (lookup table)
AccountIndexの値の大きさに依存して、1, 2, 3, 8 bytes => 1, 3, 5, 9bytesにaddressがencode。
32bytesのAccount IDであれば33 bytesにaddressがencode。
Balance moduleによりAccountIndex => AccountIdのtranslationができる。
AccountのbalanceがゼロになるとAccountIndexはreuseされる。
Signing Payload
64bytes
8bytes: Transaction Index
2+ bytes: Function Descriptor
2 bytes: Transaction Era
32 bytes: hash of the authoring block
exmaples
Set of libs for the substrate runtime.
Proof of Existence Blockchain built on Parity's Substrate
Substrate implementation of the AdEx Protocol v4: OUTPACE & Registry
Substrate node implementing all our edgeware features.
Shasper beacon chain implementation using the Substrate framework.
A new SRML-based Substrate node, ready for hacking
Teams building on Polkadot
Experimental Substrate module for multisignature wallet management
An implementation of ERC721 built on Parity Substrate
substrate-erc20
substrate-erc20-multi
Dockerized websocket listener for substrate events; also writes filtered event data to configured storage.
Private transactions
utxo
srml vs smart contract
A smart contract is good for small piece of business logic with limited scope for on-chain processing where you don't mind forcing your users to buy utility in your code from disinterested economic actors under a general computation/storage cost model. A smart-contract environment is essentially for a lot of small, fast-changing, co-dependent pieces of business logic.
Conversely if your business logic is "fairly" mature, larger, more complex, less dependent on "peer" pieces of logic or has requirements that need a much more efficient economic per-per-compute model, then runtime modules are likely to be a better fit.
Runtime modules are a little harder to code, deploy and interoperation with non-aligned economic logic (i.e. other deployers of smart contracts/runtime modules) is harder, but you get essentially "free" gas, near-native efficiency and a richer programming environment.
andriy.tyurnikov
Gav: Thanks for your input. May one say that SRML also implies ...significant power/influence of module's author within particular blockchain, as security risks of SRML are ... more impactful?
A
GavParity Technologies (+parity:matrix.parity.io)
I expect smart contracts to eventually settle into usage for prototyping and as sort of economic logic plugins, whereas specialised blockchains & runtime modules will be for production-level, mature and/or more sophisticated products.
A
02:48
Runtime modules can certainly do a lot more damage to a chain than a smart contract; but the fact a smart contract runs in a sandbox is both a blessing (it's safe/secure) and a curse (it's slow).
For smart contracts vs runtime modules, I think smart contract can also act as a plug-in or the extension point for runtime modules. e.g. the balance module can call on user supplied smart contract every time this user received some funds (maybe with a low gas limit for reasons). Then the runtime modules can be designed to be extensible and user able to customize it with smart contracts.
extrinsic
https://gyazo.com/db357d75411974d3693be58090dbc899
impl_runtime_apis!マクロでRuntimestructにblock_builder_api::BlockBuilder traitを実装
code:1.rs
decl_runtime_apis! {
/// The BlockBuilder api trait that provides required functions for building a block for a runtime.
pub trait BlockBuilder {
/// Apply the given extrinsics.
fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyResult;
/// Finish the current block.
fn finalise_block() -> <Block as BlockT>::Header;
/// Generate inherent extrinsics. The inherent data will vary from chain to chain.
fn inherent_extrinsics(inherent: InherentData) -> Vec<<Block as BlockT>::Extrinsic>;
/// Check that the inherents are valid. The inherent data will vary from chain to chain.
fn check_inherents(block: Block, data: InherentData) -> CheckInherentsResult;
/// Generate a random seed.
fn random_seed() -> <Block as BlockT>::Hash;
}
}
<storage::UncheckedExtrinsics>::count()で列挙型のどのextrinsicをapplyするか選択。
srml_executeのextrinsic apply関数。
code:2.rs
/// Actually apply an extrinsic given its encoded_len; this doesn't note its hash.
fn apply_extrinsic_no_note_with_len(uxt: Block::Extrinsic, encoded_len: usize) -> result::Result<internal::ApplyOutcome, internal::ApplyError> {
// Verify the signature is good.
let xt = uxt.check(&Default::default()).map_err(internal::ApplyError::BadSignature)?;
if let (Some(sender), Some(index)) = (xt.sender(), xt.index()) {
// check index
let expected_index = <system::Module<System>>::account_nonce(sender);
if index != &expected_index { return Err(
if index < &expected_index { internal::ApplyError::Stale } else { internal::ApplyError::Future }
) }
// pay any fees.
Payment::make_payment(sender, encoded_len).map_err(|_| internal::ApplyError::CantPay)?;
// AUDIT: Under no circumstances may this function panic from here onwards.
// increment nonce in storage
<system::Module<System>>::inc_account_nonce(sender);
}
// decode parameters and dispatch
let (f, s) = xt.deconstruct();
let r = f.dispatch(s.into());
<system::Module<System>>::note_applied_extrinsic(&r);
r.map(|_| internal::ApplyOutcome::Success).or_else(|e| Ok(internal::ApplyOutcome::Fail(e)))
}
parity_codecが使えるよう#[derive(Encode, Decode, Default)]をつけてstructでtxを外部で定義しruntimeでtxを内包するBlock::Extrinsicenumを定義
native clientで動かす場合、serdeのSerializeとDeserializeをderiveする必要がある。wasm runtimeの場合は必要ないので、std featureをつけてserdeは動かす。
flow of tx
lisning for txs on the network
validate_transaction関数にそれぞれのtxを通して検証しtx poolへput
sig, nonceが正しいか
DoSを防ぐためmodulesのcallはcheckせずにpoolのorderを決めるために必要な情報のみを検証
poolにあるreadyなtxがBlockBuilderに通りblockが作られていく。
BlockBuilderはapply_extrinsic関数を実行しtxを実行、local memoryの状態遷移をapplyする。
完成したblockがnetworkにpublishされる。
受け取ったnodeはexecute_blockを実行しsucceedsするかfailsするかチェック
execute_block should never panic
storageを書き換える前に全ての検証を行う。
AuthorityId: for consensus
AccountId: for user
oo7-substrate
substrateのchainはnodeへのentry-pointsを含むwasm binary blob runtimeを持つ。
entry-pointsはAPIセットとしてまとめられAPI traitsとして存在する。execute_blockとversionはCore API trait
Rustの場合はimpl_apis macroがruntimesを構築するために楽
code:1.rs
/// Ensure that the origin o represents a signed extrinsic (i.e. transaction).
/// Returns Ok with the account that signed the extrinsic or an Err otherwise.
pub fn ensure_signed<OuterOrigin, AccountId>(o: OuterOrigin) -> Result<AccountId, &'static str>
where OuterOrigin: Into<Option<RawOrigin<AccountId>>>
{
match o.into() {
Some(RawOrigin::Signed(t)) => Ok(t),
_ => Err("bad origin: expected to be a signed origin"),
}
}
So it's actually not that simple. The difference is not only between std or no-std, these environments are super different, because one links directly against the node, it works in the same address space as the node and another is built as a almost-completely standalone binary, which has its own address space, all interaction with the external world is performed through a mechanism similar to syscalls, and finally compiled to a architecture which almost 100% is different from the native one. I think this justifies usage of conditional compilation.
decl_runtime_apis!macroでapi traitを定義するとimpl_runtime_apis!でendpointsを実装可能
constract_runtime!でModuleを含めてruntimeを生成する。
クライアントがアップデートしていなかったら、updatedなclientから生成されたblockはrejectする。
将来的にwasm runtimeとしてV8やSpiderMonkeyを利用する。
determinism issue
For nowではcorrectness-oriented (not perdormance-oriented)なwasm interpreterを実装(wasmi)
you can define your own Transaction type here, too
but keeping AccountIds are pretty important for any chain that will run without polkadot
since you need some way to identify validators
i guess in principle, you could just have hard-coded AuithorityIds
or derive AuthorityId from a PoW
Off-chain logic would be easily integratable with on-chain logic, in the same file, compiled into the same target in the same library, able to use the same storage. Precisely when and by whom the off-chain logic is called, is a different matter. Initially, it'll be chain-validators placing the results on-chain through an Inherent, but it could eventually be arbitrary groups of actors, properly incentivised and placing data on-chain through normal transactions.
But there's nothing in block production, beyond the system of inherents, that ensures the data is especially true.
This is the same system that we use for injecting other real-world data onto the chain e.g. timestamps and offline-validator reporting
So it should be fairly robust, but it kind of depends on what it's being used for. You might still want some kind of fallback.
encodable size with parity-codec
impl_array!(1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 40 48 56 64 72 96 128 160 192 224 256);
yudetamago.icon > Rustはいいぞ