mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 07:01:05 +00:00
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:
committed by
Gavin Wood
parent
0cae7217d8
commit
feecfc856d
@@ -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
|
||||
|
||||
@@ -847,12 +847,7 @@ impl<'a> ::serde::Deserialize<'a> for OpaqueExtrinsic {
|
||||
|
||||
impl traits::Extrinsic for OpaqueExtrinsic {
|
||||
type Call = ();
|
||||
|
||||
fn is_signed(&self) -> Option<bool> {
|
||||
None
|
||||
}
|
||||
|
||||
fn new_unsigned(_call: Self::Call) -> Option<Self> { None }
|
||||
type SignaturePayload = ();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -187,6 +187,7 @@ pub struct ExtrinsicWrapper<Xt>(Xt);
|
||||
|
||||
impl<Xt> traits::Extrinsic for ExtrinsicWrapper<Xt> {
|
||||
type Call = ();
|
||||
type SignaturePayload = ();
|
||||
|
||||
fn is_signed(&self) -> Option<bool> {
|
||||
None
|
||||
@@ -274,13 +275,14 @@ impl<Call: Codec + Sync + Send, Context, Extra> Checkable<Context> for TestXt<Ca
|
||||
}
|
||||
impl<Call: Codec + Sync + Send, Extra> traits::Extrinsic for TestXt<Call, Extra> {
|
||||
type Call = Call;
|
||||
type SignaturePayload = (u64, Extra);
|
||||
|
||||
fn is_signed(&self) -> Option<bool> {
|
||||
Some(self.0.is_some())
|
||||
}
|
||||
|
||||
fn new_unsigned(_c: Call) -> Option<Self> {
|
||||
None
|
||||
fn new(c: Call, sig: Option<Self::SignaturePayload>) -> Option<Self> {
|
||||
Some(TestXt(sig, c))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -743,13 +743,24 @@ pub trait Extrinsic: Sized {
|
||||
/// The function call.
|
||||
type Call;
|
||||
|
||||
/// The payload we carry for signed extrinsics.
|
||||
///
|
||||
/// Usually it will contain a `Signature` and
|
||||
/// may include some additional data that are specific to signed
|
||||
/// extrinsics.
|
||||
type SignaturePayload;
|
||||
|
||||
/// Is this `Extrinsic` signed?
|
||||
/// If no information are available about signed/unsigned, `None` should be returned.
|
||||
fn is_signed(&self) -> Option<bool> { None }
|
||||
|
||||
/// New instance of an unsigned extrinsic aka "inherent". `None` if this is an opaque
|
||||
/// extrinsic type.
|
||||
fn new_unsigned(_call: Self::Call) -> Option<Self> { None }
|
||||
/// Create new instance of the extrinsic.
|
||||
///
|
||||
/// Extrinsics can be split into:
|
||||
/// 1. Inherents (no signature; created by validators during block production)
|
||||
/// 2. Unsigned Transactions (no signature; represent "system calls" or other special kinds of calls)
|
||||
/// 3. Signed Transactions (with signature; a regular transactions with known origin)
|
||||
fn new(_call: Self::Call, _signed_data: Option<Self::SignaturePayload>) -> Option<Self> { None }
|
||||
}
|
||||
|
||||
/// Extract the hashing type for a block.
|
||||
|
||||
@@ -141,6 +141,7 @@ impl BlindCheckable for Extrinsic {
|
||||
|
||||
impl ExtrinsicT for Extrinsic {
|
||||
type Call = Extrinsic;
|
||||
type SignaturePayload = ();
|
||||
|
||||
fn is_signed(&self) -> Option<bool> {
|
||||
if let Extrinsic::IncludeData(_) = *self {
|
||||
@@ -150,7 +151,7 @@ impl ExtrinsicT for Extrinsic {
|
||||
}
|
||||
}
|
||||
|
||||
fn new_unsigned(call: Self::Call) -> Option<Self> {
|
||||
fn new(call: Self::Call, _signature_payload: Option<Self::SignaturePayload>) -> Option<Self> {
|
||||
Some(call)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user