Submit (& sign) extrinsics from the runtime. (#3514)

* Abstract constructing extrinsic and signing.

* Initial impl of signer.

* Implement get payload.

* Clean up the code.

* Improve docs.

* Bump version.

* Update core/sr-primitives/src/generic/unchecked_extrinsic.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Fix tests & address grumbles.

* Fix build.

* Fix runtime tests.

* Fix bound test.

* Fix bound test.
This commit is contained in:
Tomasz Drwięga
2019-09-01 02:19:04 +02:00
committed by Gavin Wood
parent 0cae7217d8
commit feecfc856d
15 changed files with 346 additions and 71 deletions
@@ -27,7 +27,7 @@ mod digest;
#[cfg(test)]
mod tests;
pub use self::unchecked_extrinsic::UncheckedExtrinsic;
pub use self::unchecked_extrinsic::{UncheckedExtrinsic, SignedPayload};
pub use self::era::{Era, Phase};
pub use self::checked_extrinsic::CheckedExtrinsic;
pub use self::header::Header;
@@ -72,12 +72,22 @@ impl<Address, Call, Signature, Extra: SignedExtension> Extrinsic
{
type Call = Call;
type SignaturePayload = (
Address,
Signature,
Extra,
);
fn is_signed(&self) -> Option<bool> {
Some(self.signature.is_some())
}
fn new_unsigned(function: Call) -> Option<Self> {
Some(UncheckedExtrinsic::new_unsigned(function))
fn new(function: Call, signed_data: Option<Self::SignaturePayload>) -> Option<Self> {
Some(if let Some((address, signature, extra)) = signed_data {
UncheckedExtrinsic::new_signed(function, address, signature, extra)
} else {
UncheckedExtrinsic::new_unsigned(function)
})
}
}
@@ -98,21 +108,18 @@ where
fn check(self, lookup: &Lookup) -> Result<Self::Checked, &'static str> {
Ok(match self.signature {
Some((signed, signature, extra)) => {
let additional_signed = extra.additional_signed()?;
let raw_payload = (self.function, extra, additional_signed);
let signed = lookup.lookup(signed)?;
let raw_payload = SignedPayload::new(self.function, extra)?;
if !raw_payload.using_encoded(|payload| {
if payload.len() > 256 {
signature.verify(&blake2_256(payload)[..], &signed)
} else {
signature.verify(payload, &signed)
}
signature.verify(payload, &signed)
}) {
return Err(crate::BAD_SIGNATURE)
}
let (function, extra, _) = raw_payload.deconstruct();
CheckedExtrinsic {
signed: Some((signed, raw_payload.1)),
function: raw_payload.0,
signed: Some((signed, extra)),
function,
}
}
None => CheckedExtrinsic {
@@ -123,6 +130,59 @@ where
}
}
/// A payload that has been signed for an unchecked extrinsics.
///
/// Note that the payload that we sign to produce unchecked extrinsic signature
/// is going to be different than the `SignaturePayload` - so the thing the extrinsic
/// actually contains.
pub struct SignedPayload<Call, Extra: SignedExtension>((
Call,
Extra,
Extra::AdditionalSigned,
));
impl<Call, Extra> SignedPayload<Call, Extra> where
Call: Encode,
Extra: SignedExtension,
{
/// Create new `SignedPayload`.
///
/// This function may fail if `additional_signed` of `Extra` is not available.
pub fn new(call: Call, extra: Extra) -> Result<Self, &'static str> {
let additional_signed = extra.additional_signed()?;
let raw_payload = (call, extra, additional_signed);
Ok(Self(raw_payload))
}
/// Create new `SignedPayload` from raw components.
pub fn from_raw(call: Call, extra: Extra, additional_signed: Extra::AdditionalSigned) -> Self {
Self((call, extra, additional_signed))
}
/// Deconstruct the payload into it's components.
pub fn deconstruct(self) -> (Call, Extra, Extra::AdditionalSigned) {
self.0
}
}
impl<Call, Extra> Encode for SignedPayload<Call, Extra> where
Call: Encode,
Extra: SignedExtension,
{
/// Get an encoded version of this payload.
///
/// Payloads longer than 256 bytes are going to be `blake2_256`-hashed.
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
self.0.using_encoded(|payload| {
if payload.len() > 256 {
f(&blake2_256(payload)[..])
} else {
f(payload)
}
})
}
}
impl<Address, Call, Signature, Extra> Decode
for UncheckedExtrinsic<Address, Call, Signature, Extra>
where