Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b042a93
Make extrinsics extensible.
gavofyork Jul 11, 2019
37f6ae0
Rest of mockup. Add tips.
gavofyork Jul 11, 2019
2e5b1f4
Fix some build issues
gavofyork Jul 11, 2019
b7646ec
Runtiem builds :)
gavofyork Jul 11, 2019
a871c9f
Substrate builds.
kianenigma Jul 12, 2019
8e7c803
Fix a doc test
gavofyork Jul 13, 2019
a824b56
Compact encoding
gavofyork Jul 13, 2019
5de080f
Extract out the era logic into an extension
gavofyork Jul 15, 2019
a8789b9
Weight Check signed extension. (#3115)
kianenigma Jul 16, 2019
7d96429
Merge remote-tracking branch 'origin/master' into gav-extensble-trans…
gavofyork Jul 16, 2019
30b4ba7
Don't use len for weight - use data.
gavofyork Jul 16, 2019
2a9c9df
Merge remote-tracking branch 'origin/master' into gav-extensble-trans…
gavofyork Jul 19, 2019
342efb5
Operational Transaction; second attempt (#3138)
kianenigma Jul 19, 2019
b8f564e
Bump transaction version
jacogr Jul 19, 2019
07fdfe2
Merge branch 'gav-extensble-transactions' of github.com:paritytech/su…
jacogr Jul 19, 2019
7f33006
Master.into()
kianenigma Jul 19, 2019
36063fe
Merge branch 'gav-extensble-transactions' of github.com:paritytech/su…
kianenigma Jul 19, 2019
7a0fbc9
Fix weight mult test.
kianenigma Jul 19, 2019
84fa279
Fix more tests and improve doc.
kianenigma Jul 19, 2019
f4d4579
Bump.
kianenigma Jul 19, 2019
def6425
Merge remote-tracking branch 'origin/master' into gav-extensble-trans…
gavofyork Jul 20, 2019
d12713a
Make some tests work again.
kianenigma Jul 20, 2019
3350f9c
Fix subkey.
kianenigma Jul 20, 2019
b788507
Remove todos + bump.
kianenigma Jul 20, 2019
c8b0053
Merge branch 'master' of github.com:paritytech/substrate into gav-ext…
kianenigma Jul 22, 2019
383185d
Ignore expensive test.
kianenigma Jul 22, 2019
ec829fd
Bump.
kianenigma Jul 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 14 additions & 24 deletions core/sr-primitives/src/generic/unchecked_extrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,8 @@ use std::fmt;
use rstd::prelude::*;
use runtime_io::blake2_256;
use crate::codec::{Decode, Encode, Input};
use crate::traits::{
self, Member, SimpleArithmetic, MaybeDisplay, CurrentHeight, SignedExtension,
BlockNumberToHash, Lookup, Checkable, Extrinsic, SaturatedConversion
};
use super::{CheckedExtrinsic, Era};
use crate::traits::{self, Member, MaybeDisplay, SignedExtension, Checkable, Extrinsic};
use super::CheckedExtrinsic;

const TRANSACTION_VERSION: u8 = 1;

Expand All @@ -40,7 +37,7 @@ where
/// The signature, address, number of extrinsics have come before from
/// the same signer and an era describing the longevity of this transaction,
/// if this is a signed extrinsic.
pub signature: Option<(Address, Signature, Era, Extra)>,
pub signature: Option<(Address, Signature, Extra)>,
/// The function that should be called.
pub function: Call,
}
Expand All @@ -53,11 +50,10 @@ impl<Address, Call, Signature, Extra: SignedExtension>
function: Call,
signed: Address,
signature: Signature,
era: Era,
extra: Extra
) -> Self {
UncheckedExtrinsic {
signature: Some((signed, signature, era, extra)),
signature: Some((signed, signature, extra)),
function,
}
}
Expand All @@ -79,8 +75,8 @@ impl<Address, Call, Signature, Extra: SignedExtension> Extrinsic
}
}

impl<Address, AccountId, Call, Signature, Extra, Context, Hash, BlockNumber>
Checkable<Context>
impl<Address, AccountId, Call, Signature, Extra, Lookup>
Checkable<Lookup>
for
UncheckedExtrinsic<Address, Call, Signature, Extra>
where
Expand All @@ -89,22 +85,16 @@ where
Signature: Member + traits::Verify<Signer=AccountId>,
Extra: SignedExtension<AccountId=AccountId>,
AccountId: Member + MaybeDisplay,
BlockNumber: SimpleArithmetic,
Hash: Encode,
Context: Lookup<Source=Address, Target=AccountId>
+ CurrentHeight<BlockNumber=BlockNumber>
+ BlockNumberToHash<BlockNumber=BlockNumber, Hash=Hash>,
Lookup: traits::Lookup<Source=Address, Target=AccountId>
{
type Checked = CheckedExtrinsic<AccountId, Call, Extra>;

fn check(self, context: &Context) -> Result<Self::Checked, &'static str> {
fn check(self, lookup: &Lookup) -> Result<Self::Checked, &'static str> {
Ok(match self.signature {
Some((signed, signature, era, extra)) => {
let current_u64 = context.current_height().saturated_into::<u64>();
let h = context.block_number_to_hash(era.birth(current_u64).saturated_into())
.ok_or("transaction birth block ancient")?;
let signed = context.lookup(signed)?;
let raw_payload = (self.function, era, h, extra);
Some((signed, signature, extra)) => {
let additional_signed = extra.additional_signed()?;
let raw_payload = (self.function, extra, additional_signed);
let signed = lookup.lookup(signed)?;
if !raw_payload.using_encoded(|payload| {
if payload.len() > 256 {
signature.verify(&blake2_256(payload)[..], &signed)
Expand All @@ -115,7 +105,7 @@ where
return Err(crate::BAD_SIGNATURE)
}
CheckedExtrinsic {
signed: Some((signed, raw_payload.3)),
signed: Some((signed, raw_payload.1)),
function: raw_payload.0,
}
}
Expand Down Expand Up @@ -200,7 +190,7 @@ where
Extra: SignedExtension,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UncheckedExtrinsic({:?}, {:?})", self.signature.as_ref().map(|x| (&x.0, &x.2, &x.3)), self.function)
write!(f, "UncheckedExtrinsic({:?}, {:?})", self.signature.as_ref().map(|x| (&x.0, &x.2)), self.function)
}
}

Expand Down
18 changes: 17 additions & 1 deletion core/sr-primitives/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,7 +813,15 @@ pub trait SignedExtension:
/// The type which encodes the sender identity.
type AccountId;

/// Validate a signed transaction for the transaction queue.
/// Any additional data that will go into the signed payload. This may be created dynamically
/// from the transaction using the `additional_signed` function.
type AdditionalSigned: Encode;

/// Construct any additional data that should be in the signed payload of the transaction. Can
/// also perform any pre-signature-verification checks and return an error if needed.
fn additional_signed(&self) -> Result<Self::AdditionalSigned, &'static str>;

/// Validate a signed transaction for the transaction queue.
fn validate(
&self,
_who: &Self::AccountId,
Expand Down Expand Up @@ -846,6 +854,12 @@ impl<
B: SignedExtension<AccountId=AccountId>,
> SignedExtension for (A, B) {
type AccountId = AccountId;
type AdditionalSigned = (A::AdditionalSigned, B::AdditionalSigned);

fn additional_signed(&self) -> Result<Self::AdditionalSigned, &'static str> {
Ok((self.0.additional_signed()?, self.1.additional_signed()?))
}

fn validate(
&self,
who: &Self::AccountId,
Expand Down Expand Up @@ -884,6 +898,8 @@ impl<
#[cfg(feature = "std")]
impl SignedExtension for () {
type AccountId = u64;
type AdditionalSigned = ();
fn additional_signed(&self) -> result::Result<(), &'static str> { Ok(()) }
}

/// An "executable" piece of information, used by the standard Substrate Executive in order to
Expand Down
22 changes: 9 additions & 13 deletions node/cli/src/factory_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,10 @@ use rand::rngs::StdRng;

use parity_codec::Decode;
use keyring::sr25519::Keyring;
use node_primitives::Hash;
use node_runtime::{Call, CheckedExtrinsic, UncheckedExtrinsic, BalancesCall};
use primitives::sr25519;
use primitives::crypto::Pair;
use node_runtime::{Call, CheckedExtrinsic, UncheckedExtrinsic, SignedExtra, BalancesCall};
use primitives::{sr25519, crypto::Pair};
use parity_codec::Encode;
use sr_primitives::generic::Era;
use sr_primitives::traits::{Block as BlockT, Header as HeaderT};
use sr_primitives::{generic::Era, traits::{Block as BlockT, Header as HeaderT, SignedExtension}};
use substrate_service::ServiceFactory;
use transaction_factory::RuntimeAdapter;
use transaction_factory::modes::Mode;
Expand Down Expand Up @@ -130,18 +127,19 @@ impl RuntimeAdapter for FactoryState<Number> {
) -> <Self::Block as BlockT>::Extrinsic {
let index = self.extract_index(&sender, prior_block_hash);
let phase = self.extract_phase(*prior_block_hash);
let era = system::CheckEra::from(Era::mortal(256, phase));
let check_nonce = system::CheckNonce::from(index);
let take_fees = balances::TakeFees::from(0);

sign::<service::Factory, Self>(CheckedExtrinsic {
signed: Some((sender.clone(), (check_nonce, take_fees))),
signed: Some((sender.clone(), (era, (check_nonce, take_fees)))),
function: Call::Balances(
BalancesCall::transfer(
indices::address::Address::Id(destination.clone().into()),
(*amount).into()
)
)
}, key, &prior_block_hash, phase)
}, key, (prior_block_hash.clone(), ((), ())))
}

fn inherent_extrinsics(&self) -> InherentData {
Expand Down Expand Up @@ -229,13 +227,11 @@ fn gen_seed_bytes(seed: u64) -> [u8; 32] {
fn sign<F: ServiceFactory, RA: RuntimeAdapter>(
xt: CheckedExtrinsic,
key: &sr25519::Pair,
prior_block_hash: &Hash,
phase: u64,
additional_signed: <SignedExtra as SignedExtension>::AdditionalSigned,
) -> <RA::Block as BlockT>::Extrinsic {
let s = match xt.signed {
Some((signed, extra)) => {
let era = Era::mortal(256, phase);
let payload = (xt.function, era, prior_block_hash, extra.clone());
let payload = (xt.function, extra.clone(), additional_signed);
let signature = payload.using_encoded(|b| {
if b.len() > 256 {
key.sign(&sr_io::blake2_256(b))
Expand All @@ -244,7 +240,7 @@ fn sign<F: ServiceFactory, RA: RuntimeAdapter>(
}
}).into();
UncheckedExtrinsic {
signature: Some((indices::address::Address::Id(signed), signature, era, extra)),
signature: Some((indices::address::Address::Id(signed), signature, extra)),
function: payload.0,
}
}
Expand Down
1 change: 1 addition & 0 deletions node/executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ mod tests {

type TestExternalities<H> = CoreTestExternalities<H, u64>;

// TODO: fix for being charged based on weight now.
fn transfer_fee(bytes: Balance) -> Balance {
<TransactionBaseFee as Get<Balance>>::get() + <TransactionByteFee as Get<Balance>>::get() * bytes
}
Expand Down
2 changes: 1 addition & 1 deletion node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ pub type SignedBlock = generic::SignedBlock<Block>;
/// BlockId type as expected by this runtime.
pub type BlockId = generic::BlockId<Block>;
/// The SignedExtension to the basic transaction logic.
pub type SignedExtra = (system::CheckNonce<Runtime>, balances::TakeFees<Runtime>);
pub type SignedExtra = (system::CheckEra<Runtime>, (system::CheckNonce<Runtime>, balances::TakeFees<Runtime>));
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
/// Extrinsic type that has already been checked.
Expand Down
5 changes: 4 additions & 1 deletion srml/balances/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1157,13 +1157,16 @@ use primitives::weights::Weight;
impl<T: Trait<I>, I: Instance + Clone + Eq> SignedExtension for TakeFees<T, I> {
type AccountId = T::AccountId;

type AdditionalSigned = ();
fn additional_signed(&self) -> rstd::result::Result<(), &'static str> { Ok(()) }

fn validate(
&self,
who: &Self::AccountId,
weight: Weight,
) -> rstd::result::Result<ValidTransaction, DispatchError> {
let fee_x = T::Balance::from(weight);
// TODO TODO: should be weight_to_fee(weight)
// TODO: should be weight_to_fee(weight)
let fee = T::TransactionBaseFee::get() + T::TransactionByteFee::get() * fee_x;
let fee = fee + self.0.clone();
let imbalance = <Module<T, I>>::withdraw(
Expand Down
38 changes: 36 additions & 2 deletions srml/system/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ use rstd::prelude::*;
#[cfg(any(feature = "std", test))]
use rstd::map;
use primitives::{
generic, weights::Weight, traits::{
generic::{self, Era}, weights::Weight, traits::{
self, CheckEqual, SimpleArithmetic, Zero, SignedExtension,
SimpleBitOps, Hash, Member, MaybeDisplay, EnsureOrigin, CurrentHeight, BlockNumberToHash,
MaybeSerializeDebugButNotDeserialize, MaybeSerializeDebug, StaticLookup, One, Bounded,
Lookup, DispatchError
Lookup, DispatchError, SaturatedConversion
}, transaction_validity::{
ValidTransaction, TransactionPriority, TransactionLongevity
},
Expand Down Expand Up @@ -774,6 +774,8 @@ impl<T: Trait> rstd::fmt::Debug for CheckNonce<T> {

impl<T: Trait> SignedExtension for CheckNonce<T> {
type AccountId = T::AccountId;
type AdditionalSigned = ();
fn additional_signed(&self) -> Result<(), &'static str> { Ok(()) }
fn pre_dispatch(
self,
who: &Self::AccountId,
Expand Down Expand Up @@ -817,6 +819,38 @@ impl<T: Trait> SignedExtension for CheckNonce<T> {
}
}


/// Nonce check and increment to give replay protection for transactions.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct CheckEra<T: Trait + Send + Sync>((Era, rstd::marker::PhantomData<T>));

#[cfg(feature = "std")]
impl<T: Trait + Send + Sync> CheckEra<T> {
/// utility constructor. Used only in client/factory code.
pub fn from(era: Era) -> Self {
Self((era, rstd::marker::PhantomData))
}
}

#[cfg(feature = "std")]
impl<T: Trait + Send + Sync> rstd::fmt::Debug for CheckEra<T> {
fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
self.0.fmt(f)
}
}

impl<T: Trait + Send + Sync> SignedExtension for CheckEra<T> {
type AccountId = T::AccountId;
type AdditionalSigned = T::Hash;
fn additional_signed(&self) -> Result<Self::AdditionalSigned, &'static str> {
let current_u64 = <Module<T>>::block_number().saturated_into::<u64>();
let n = (self.0).0.birth(current_u64).saturated_into::<T::BlockNumber>();
if !<BlockHash<T>>::exists(n) { Err("transaction birth block ancient")? }
Ok(<Module<T>>::block_hash(n))
}
}


pub struct ChainContext<T>(::rstd::marker::PhantomData<T>);
impl<T> Default for ChainContext<T> {
fn default() -> Self {
Expand Down