Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
parity
Mirrored projects
polkadot
Commits
ab08eb78
Unverified
Commit
ab08eb78
authored
Aug 30, 2018
by
Gav Wood
Committed by
GitHub
Aug 30, 2018
Browse files
Merge pull request #7 from paritytech/rh-testnet-fp
Forward-port of various testnet fixes
parents
5a684a58
d25f3b0d
Changes
9
Hide whitespace changes
Inline
Side-by-side
Cargo.lock
View file @
ab08eb78
...
@@ -1705,6 +1705,7 @@ name = "polkadot-api"
...
@@ -1705,6 +1705,7 @@ name = "polkadot-api"
version = "0.1.0"
version = "0.1.0"
dependencies = [
dependencies = [
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"polkadot-executor 0.1.0",
"polkadot-executor 0.1.0",
"polkadot-primitives 0.1.0",
"polkadot-primitives 0.1.0",
"polkadot-runtime 0.1.0",
"polkadot-runtime 0.1.0",
...
...
api/Cargo.toml
View file @
ab08eb78
...
@@ -16,6 +16,7 @@ substrate-client = { git = "https://github.com/paritytech/substrate" }
...
@@ -16,6 +16,7 @@ substrate-client = { git = "https://github.com/paritytech/substrate" }
substrate-primitives
=
{
git
=
"https://github.com/paritytech/substrate"
}
substrate-primitives
=
{
git
=
"https://github.com/paritytech/substrate"
}
substrate-executor
=
{
git
=
"https://github.com/paritytech/substrate"
}
substrate-executor
=
{
git
=
"https://github.com/paritytech/substrate"
}
substrate-state-machine
=
{
git
=
"https://github.com/paritytech/substrate"
}
substrate-state-machine
=
{
git
=
"https://github.com/paritytech/substrate"
}
log
=
"0.3"
[dev-dependencies]
[dev-dependencies]
substrate-keyring
=
{
git
=
"https://github.com/paritytech/substrate"
}
substrate-keyring
=
{
git
=
"https://github.com/paritytech/substrate"
}
api/src/full.rs
View file @
ab08eb78
...
@@ -97,18 +97,33 @@ impl<B: LocalBackend<Block, KeccakHasher, RlpCodec>> PolkadotApi for Client<B, L
...
@@ -97,18 +97,33 @@ impl<B: LocalBackend<Block, KeccakHasher, RlpCodec>> PolkadotApi for Client<B, L
fn
evaluate_block
(
&
self
,
at
:
&
BlockId
,
block
:
Block
)
->
Result
<
bool
>
{
fn
evaluate_block
(
&
self
,
at
:
&
BlockId
,
block
:
Block
)
->
Result
<
bool
>
{
use
substrate_executor
::
error
::
ErrorKind
as
ExecErrorKind
;
use
substrate_executor
::
error
::
ErrorKind
as
ExecErrorKind
;
use
codec
::{
Decode
,
Encode
};
use
codec
::
Encode
;
use
runtime
::
Block
as
RuntimeBlock
;
use
state_machine
::
ExecutionManager
;
use
client
::
CallExecutor
;
let
parent
=
at
;
let
res
=
self
.state_at
(
&
parent
)
.map_err
(
Error
::
from
)
.and_then
(|
state
|
{
let
mut
overlay
=
Default
::
default
();
let
execution_manager
=
||
ExecutionManager
::
Both
(|
wasm_result
,
native_result
|
{
warn!
(
"Consensus error between wasm and native runtime execution at block {:?}"
,
at
);
warn!
(
" While executing block {:?}"
,
(
block
.header.number
,
block
.header
.hash
()));
warn!
(
" Native result {:?}"
,
native_result
);
warn!
(
" Wasm result {:?}"
,
wasm_result
);
wasm_result
});
let
(
r
,
_
)
=
self
.executor
()
.call_at_state
(
&
state
,
&
mut
overlay
,
"execute_block"
,
&
block
.encode
(),
execution_manager
()
)
?
;
Ok
(
r
)
});
let
encoded
=
block
.encode
();
let
runtime_block
=
match
RuntimeBlock
::
decode
(
&
mut
&
encoded
[
..
])
{
Some
(
x
)
=>
x
,
None
=>
return
Ok
(
false
),
};
let
res
=
with_runtime!
(
self
,
at
,
||
::
runtime
::
Executive
::
execute_block
(
runtime_block
));
match
res
{
match
res
{
Ok
(
()
)
=>
Ok
(
true
),
Ok
(
_
)
=>
Ok
(
true
),
Err
(
err
)
=>
match
err
.kind
()
{
Err
(
err
)
=>
match
err
.kind
()
{
&
ErrorKind
::
Executor
(
ExecErrorKind
::
Runtime
)
=>
Ok
(
false
),
&
ErrorKind
::
Executor
(
ExecErrorKind
::
Runtime
)
=>
Ok
(
false
),
_
=>
Err
(
err
)
_
=>
Err
(
err
)
...
@@ -148,8 +163,10 @@ impl<B: LocalBackend<Block, KeccakHasher, RlpCodec>> PolkadotApi for Client<B, L
...
@@ -148,8 +163,10 @@ impl<B: LocalBackend<Block, KeccakHasher, RlpCodec>> PolkadotApi for Client<B, L
fn
inherent_extrinsics
(
&
self
,
at
:
&
BlockId
,
inherent_data
:
InherentData
)
->
Result
<
Vec
<
UncheckedExtrinsic
>>
{
fn
inherent_extrinsics
(
&
self
,
at
:
&
BlockId
,
inherent_data
:
InherentData
)
->
Result
<
Vec
<
UncheckedExtrinsic
>>
{
use
codec
::{
Encode
,
Decode
};
use
codec
::{
Encode
,
Decode
};
let
runtime_version
=
self
.runtime_version_at
(
at
)
?
;
with_runtime!
(
self
,
at
,
||
{
with_runtime!
(
self
,
at
,
||
{
let
extrinsics
=
::
runtime
::
inherent_extrinsics
(
inherent_data
);
let
extrinsics
=
::
runtime
::
inherent_extrinsics
(
inherent_data
,
runtime_version
);
extrinsics
.into_iter
()
extrinsics
.into_iter
()
.map
(|
x
|
x
.encode
())
// get encoded representation
.map
(|
x
|
x
.encode
())
// get encoded representation
.map
(|
x
|
Decode
::
decode
(
&
mut
&
x
[
..
]))
// get byte-vec equivalent to extrinsic
.map
(|
x
|
Decode
::
decode
(
&
mut
&
x
[
..
]))
// get byte-vec equivalent to extrinsic
...
@@ -229,6 +246,7 @@ mod tests {
...
@@ -229,6 +246,7 @@ mod tests {
assert_eq!
(
block
.header.number
,
1
);
assert_eq!
(
block
.header.number
,
1
);
assert!
(
block
.header.extrinsics_root
!=
Default
::
default
());
assert!
(
block
.header.extrinsics_root
!=
Default
::
default
());
assert!
(
client
.evaluate_block
(
&
id
,
block
)
.unwrap
());
}
}
#[test]
#[test]
...
@@ -251,6 +269,7 @@ mod tests {
...
@@ -251,6 +269,7 @@ mod tests {
assert_eq!
(
block
.header.number
,
1
);
assert_eq!
(
block
.header.number
,
1
);
assert!
(
block
.header.extrinsics_root
!=
Default
::
default
());
assert!
(
block
.header.extrinsics_root
!=
Default
::
default
());
assert!
(
client
.evaluate_block
(
&
id
,
block
)
.unwrap
());
}
}
#[test]
#[test]
...
...
api/src/lib.rs
View file @
ab08eb78
...
@@ -32,6 +32,9 @@ extern crate substrate_state_machine as state_machine;
...
@@ -32,6 +32,9 @@ extern crate substrate_state_machine as state_machine;
#[macro_use]
#[macro_use]
extern
crate
error_chain
;
extern
crate
error_chain
;
#[macro_use]
extern
crate
log
;
#[cfg(test)]
#[cfg(test)]
extern
crate
substrate_keyring
as
keyring
;
extern
crate
substrate_keyring
as
keyring
;
...
...
consensus/src/offline_tracker.rs
View file @
ab08eb78
...
@@ -21,14 +21,18 @@ use polkadot_primitives::AccountId;
...
@@ -21,14 +21,18 @@ use polkadot_primitives::AccountId;
use
std
::
collections
::
HashMap
;
use
std
::
collections
::
HashMap
;
use
std
::
time
::{
Instant
,
Duration
};
use
std
::
time
::{
Instant
,
Duration
};
// time before we report a validator.
const
REPORT_TIME
:
Duration
=
Duration
::
from_secs
(
60
*
5
);
struct
Observed
{
struct
Observed
{
last_round_end
:
Instant
,
last_round_end
:
Instant
,
offline_since
:
Instant
,
offline_since
:
Instant
,
}
}
#[derive(Eq,
PartialEq)]
enum
Activity
{
Offline
,
StillOffline
(
Duration
),
Online
,
}
impl
Observed
{
impl
Observed
{
fn
new
()
->
Observed
{
fn
new
()
->
Observed
{
let
now
=
Instant
::
now
();
let
now
=
Instant
::
now
();
...
@@ -38,31 +42,32 @@ impl Observed {
...
@@ -38,31 +42,32 @@ impl Observed {
}
}
}
}
fn
note_round_end
(
&
mut
self
,
was_online
:
bool
)
{
fn
note_round_end
(
&
mut
self
,
now
:
Instant
,
was_online
:
Option
<
bool
>
)
{
let
now
=
Instant
::
now
();
self
.last_round_end
=
now
;
self
.last_round_end
=
now
;
if
was_online
{
if
let
Some
(
false
)
=
was_online
{
self
.offline_since
=
now
;
self
.offline_since
=
now
;
}
}
}
}
fn
is_active
(
&
self
)
->
bool
{
/// Returns what we have observed about the online/offline state of the validator.
fn
activity
(
&
self
)
->
Activity
{
// can happen if clocks are not monotonic
// can happen if clocks are not monotonic
if
self
.offline_since
>
self
.last_round_end
{
return
true
}
if
self
.offline_since
>
self
.last_round_end
{
return
Activity
::
Online
}
self
.last_round_end
.duration_since
(
self
.offline_since
)
<
REPORT_TIME
if
self
.offline_since
==
self
.last_round_end
{
return
Activity
::
Offline
}
Activity
::
StillOffline
(
self
.last_round_end
.duration_since
(
self
.offline_since
))
}
}
}
}
/// Tracks offline validators and can issue a report for those offline.
/// Tracks offline validators and can issue a report for those offline.
pub
struct
OfflineTracker
{
pub
struct
OfflineTracker
{
observed
:
HashMap
<
AccountId
,
Observed
>
,
observed
:
HashMap
<
AccountId
,
Observed
>
,
block_instant
:
Instant
,
}
}
impl
OfflineTracker
{
impl
OfflineTracker
{
/// Create a new tracker.
/// Create a new tracker.
pub
fn
new
()
->
Self
{
pub
fn
new
()
->
Self
{
OfflineTracker
{
observed
:
HashMap
::
new
()
}
OfflineTracker
{
observed
:
HashMap
::
new
()
,
block_instant
:
Instant
::
now
()
}
}
}
/// Note new consensus is starting with the given set of validators.
/// Note new consensus is starting with the given set of validators.
...
@@ -71,23 +76,33 @@ impl OfflineTracker {
...
@@ -71,23 +76,33 @@ impl OfflineTracker {
let
set
:
HashSet
<
_
>
=
validators
.iter
()
.cloned
()
.collect
();
let
set
:
HashSet
<
_
>
=
validators
.iter
()
.cloned
()
.collect
();
self
.observed
.retain
(|
k
,
_
|
set
.contains
(
k
));
self
.observed
.retain
(|
k
,
_
|
set
.contains
(
k
));
self
.block_instant
=
Instant
::
now
();
}
}
/// Note that a round has ended.
/// Note that a round has ended.
pub
fn
note_round_end
(
&
mut
self
,
validator
:
AccountId
,
was_online
:
bool
)
{
pub
fn
note_round_end
(
&
mut
self
,
validator
:
AccountId
,
was_online
:
bool
)
{
self
.observed
.entry
(
validator
)
self
.observed
.entry
(
validator
)
.or_insert_with
(
Observed
::
new
);
.or_insert_with
(
Observed
::
new
)
for
(
val
,
obs
)
in
self
.observed
.iter_mut
()
{
.note_round_end
(
was_online
);
obs
.note_round_end
(
self
.block_instant
,
if
val
==
&
validator
{
Some
(
was_online
)
}
else
{
None
}
)
}
}
}
/// Generate a vector of indices for offline account IDs.
/// Generate a vector of indices for offline account IDs.
pub
fn
reports
(
&
self
,
validators
:
&
[
AccountId
])
->
Vec
<
u32
>
{
pub
fn
reports
(
&
self
,
validators
:
&
[
AccountId
])
->
Vec
<
u32
>
{
validators
.iter
()
validators
.iter
()
.enumerate
()
.enumerate
()
.filter_map
(|(
i
,
v
)|
if
self
.is_online
(
v
)
{
.filter_map
(|(
i
,
v
)|
if
self
.is_known_offline_now
(
v
)
{
None
}
else
{
Some
(
i
as
u32
)
Some
(
i
as
u32
)
}
else
{
None
})
})
.collect
()
.collect
()
}
}
...
@@ -101,13 +116,15 @@ impl OfflineTracker {
...
@@ -101,13 +116,15 @@ impl OfflineTracker {
};
};
// we must think all validators reported externally are offline.
// we must think all validators reported externally are offline.
let
thinks_online
=
self
.is_online
(
v
);
self
.is_known_offline_now
(
v
)
!
thinks_online
})
})
}
}
fn
is_online
(
&
self
,
v
:
&
AccountId
)
->
bool
{
/// Rwturns true only if we have seen the validator miss the last round. For further
self
.observed
.get
(
v
)
.map
(
Observed
::
is_active
)
.unwrap_or
(
true
)
/// rounds where we can't say for sure that they're still offline, we give them the
/// benefit of the doubt.
fn
is_known_offline_now
(
&
self
,
v
:
&
AccountId
)
->
bool
{
self
.observed
.get
(
v
)
.map
(|
o
|
o
.activity
()
==
Activity
::
Offline
)
.unwrap_or
(
false
)
}
}
}
}
...
@@ -121,17 +138,30 @@ mod tests {
...
@@ -121,17 +138,30 @@ mod tests {
let
v
=
[
0
;
32
]
.into
();
let
v
=
[
0
;
32
]
.into
();
let
v2
=
[
1
;
32
]
.into
();
let
v2
=
[
1
;
32
]
.into
();
let
v3
=
[
2
;
32
]
.into
();
let
v3
=
[
2
;
32
]
.into
();
tracker
.note_new_block
(
&
[
v
,
v2
,
v3
]);
tracker
.note_round_end
(
v
,
true
);
tracker
.note_round_end
(
v
,
true
);
tracker
.note_round_end
(
v2
,
true
);
tracker
.note_round_end
(
v2
,
true
);
tracker
.note_round_end
(
v3
,
true
);
tracker
.note_round_end
(
v3
,
true
);
assert_eq!
(
tracker
.reports
(
&
[
v
,
v2
,
v3
]),
vec!
[
0u32
;
0
]);
tracker
.note_new_block
(
&
[
v
,
v2
,
v3
]);
tracker
.note_round_end
(
v
,
true
);
tracker
.note_round_end
(
v2
,
false
);
tracker
.note_round_end
(
v3
,
true
);
assert_eq!
(
tracker
.reports
(
&
[
v
,
v2
,
v3
]),
vec!
[
1
]);
let
slash_time
=
REPORT_TIME
+
Duration
::
from_secs
(
5
);
tracker
.note_new_block
(
&
[
v
,
v2
,
v3
]
);
tracker
.
observed
.get_mut
(
&
v
)
.unwrap
()
.offline_since
-=
slash_time
;
tracker
.
note_round_end
(
v
,
false
)
;
tracker
.observed
.get_mut
(
&
v2
)
.unwrap
()
.offline_since
-=
slash_time
;
assert_eq!
(
tracker
.reports
(
&
[
v
,
v2
,
v3
]),
vec!
[
0
])
;
assert_eq!
(
tracker
.reports
(
&
[
v
,
v2
,
v3
]),
vec!
[
0
,
1
]);
tracker
.note_new_block
(
&
[
v
,
v2
,
v3
]);
tracker
.note_round_end
(
v
,
false
);
tracker
.note_round_end
(
v2
,
true
);
tracker
.note_round_end
(
v3
,
false
);
assert_eq!
(
tracker
.reports
(
&
[
v
,
v2
,
v3
]),
vec!
[
0
,
2
]);
tracker
.note_new_block
(
&
[
v
,
v3
]);
tracker
.note_new_block
(
&
[
v
,
v2
]);
tracker
.note_round_end
(
v
,
false
);
assert_eq!
(
tracker
.reports
(
&
[
v
,
v2
,
v3
]),
vec!
[
0
]);
assert_eq!
(
tracker
.reports
(
&
[
v
,
v2
,
v3
]),
vec!
[
0
]);
}
}
}
}
consensus/src/service.rs
View file @
ab08eb78
...
@@ -62,32 +62,26 @@ fn start_bft<F, C>(
...
@@ -62,32 +62,26 @@ fn start_bft<F, C>(
const
DELAY_UNTIL
:
Duration
=
Duration
::
from_millis
(
5000
);
const
DELAY_UNTIL
:
Duration
=
Duration
::
from_millis
(
5000
);
let
mut
handle
=
LocalThreadHandle
::
current
();
let
mut
handle
=
LocalThreadHandle
::
current
();
let
work
=
Delay
::
new
(
Instant
::
now
()
+
DELAY_UNTIL
)
match
bft_service
.build_upon
(
&
header
)
{
.then
(
move
|
res
|
{
Ok
(
Some
(
bft_work
))
=>
{
if
let
Err
(
e
)
=
res
{
// do not poll work for some amount of time.
warn!
(
target
:
"bft"
,
"Failed to force delay of consensus: {:?}"
,
e
);
let
work
=
Delay
::
new
(
Instant
::
now
()
+
DELAY_UNTIL
)
.then
(
move
|
res
|
{
}
if
let
Err
(
e
)
=
res
{
warn!
(
target
:
"bft"
,
"Failed to force delay of consensus: {:?}"
,
e
);
}
match
bft_service
.build_upon
(
&
header
)
{
debug!
(
target
:
"bft"
,
"Starting agreement. After forced delay for {:?}"
,
Ok
(
maybe_bft_work
)
=>
{
DELAY_UNTIL
);
if
maybe_bft_work
.is_some
()
{
debug!
(
target
:
"bft"
,
"Starting agreement. After forced delay for {:?}"
,
DELAY_UNTIL
);
}
maybe_bft_work
bft_work
}
});
Err
(
e
)
=>
{
if
let
Err
(
e
)
=
handle
.spawn_local
(
Box
::
new
(
work
))
{
warn!
(
target
:
"bft"
,
"BFT agreement error: {}"
,
e
);
warn!
(
target
:
"bft"
,
"Couldn't initialize BFT agreement: {:?}"
,
e
);
None
}
}
}
})
}
.map
(|
_
|
());
Ok
(
None
)
=>
trace!
(
target
:
"bft"
,
"Could not start agreement on top of {}"
,
header
.hash
()),
Err
(
e
)
=>
warn!
(
target
:
"bft"
,
"BFT agreement error: {}"
,
e
),
if
let
Err
(
e
)
=
handle
.spawn_local
(
Box
::
new
(
work
))
{
}
debug!
(
target
:
"bft"
,
"Couldn't initialize BFT agreement: {:?}"
,
e
);
}
}
}
// creates a task to prune redundant entries in availability store upon block finalization
// creates a task to prune redundant entries in availability store upon block finalization
...
@@ -198,6 +192,7 @@ impl Service {
...
@@ -198,6 +192,7 @@ impl Service {
client
.import_notification_stream
()
.for_each
(
move
|
notification
|
{
client
.import_notification_stream
()
.for_each
(
move
|
notification
|
{
if
notification
.is_new_best
{
if
notification
.is_new_best
{
trace!
(
target
:
"bft"
,
"Attempting to start new consensus round after import notification of {:?}"
,
notification
.hash
);
start_bft
(
notification
.header
,
bft_service
.clone
());
start_bft
(
notification
.header
,
bft_service
.clone
());
}
}
Ok
(())
Ok
(())
...
@@ -221,14 +216,12 @@ impl Service {
...
@@ -221,14 +216,12 @@ impl Service {
let
c
=
client
.clone
();
let
c
=
client
.clone
();
let
s
=
bft_service
.clone
();
let
s
=
bft_service
.clone
();
interval
.map_err
(|
e
|
debug!
(
"Timer error: {:?}"
,
e
))
.for_each
(
move
|
_
|
{
interval
.map_err
(|
e
|
debug!
(
target
:
"bft"
,
"Timer error: {:?}"
,
e
))
.for_each
(
move
|
_
|
{
if
let
Ok
(
best_block
)
=
c
.best_block_header
()
{
if
let
Ok
(
best_block
)
=
c
.best_block_header
()
{
let
hash
=
best_block
.hash
();
let
hash
=
best_block
.hash
();
let
last_agreement
=
s
.last_agreement
();
let
can_build_upon
=
last_agreement
if
hash
==
prev_best
{
.map_or
(
true
,
|
x
|
!
x
.live
||
x
.parent_hash
!=
hash
);
debug!
(
target
:
"bft"
,
"Starting consensus round after a timeout"
);
if
hash
==
prev_best
&&
can_build_upon
{
debug!
(
"Starting consensus round after a timeout"
);
start_bft
(
best_block
,
s
.clone
());
start_bft
(
best_block
,
s
.clone
());
}
}
prev_best
=
hash
;
prev_best
=
hash
;
...
...
primitives/src/lib.rs
View file @
ab08eb78
...
@@ -120,4 +120,4 @@ pub struct InherentData {
...
@@ -120,4 +120,4 @@ pub struct InherentData {
pub
parachain_heads
:
Vec
<
::
parachain
::
CandidateReceipt
>
,
pub
parachain_heads
:
Vec
<
::
parachain
::
CandidateReceipt
>
,
/// Indices of offline validators.
/// Indices of offline validators.
pub
offline_indices
:
Vec
<
u32
>
,
pub
offline_indices
:
Vec
<
u32
>
,
}
}
\ No newline at end of file
runtime/src/lib.rs
View file @
ab08eb78
...
@@ -250,7 +250,7 @@ pub mod api {
...
@@ -250,7 +250,7 @@ pub mod api {
apply_extrinsic
=>
|
extrinsic
|
super
::
Executive
::
apply_extrinsic
(
extrinsic
),
apply_extrinsic
=>
|
extrinsic
|
super
::
Executive
::
apply_extrinsic
(
extrinsic
),
execute_block
=>
|
block
|
super
::
Executive
::
execute_block
(
block
),
execute_block
=>
|
block
|
super
::
Executive
::
execute_block
(
block
),
finalise_block
=>
|()|
super
::
Executive
::
finalise_block
(),
finalise_block
=>
|()|
super
::
Executive
::
finalise_block
(),
inherent_extrinsics
=>
|
inherent
|
super
::
inherent_extrinsics
(
inherent
),
inherent_extrinsics
=>
|
(
inherent
,
version
)
|
super
::
inherent_extrinsics
(
inherent
,
version
),
validator_count
=>
|()|
super
::
Session
::
validator_count
(),
validator_count
=>
|()|
super
::
Session
::
validator_count
(),
validators
=>
|()|
super
::
Session
::
validators
()
validators
=>
|()|
super
::
Session
::
validators
()
);
);
...
...
runtime/src/utils.rs
View file @
ab08eb78
...
@@ -22,9 +22,10 @@ use runtime_primitives::traits::{Checkable, AuxLookup};
...
@@ -22,9 +22,10 @@ use runtime_primitives::traits::{Checkable, AuxLookup};
use
timestamp
::
Call
as
TimestampCall
;
use
timestamp
::
Call
as
TimestampCall
;
use
parachains
::
Call
as
ParachainsCall
;
use
parachains
::
Call
as
ParachainsCall
;
use
session
::
Call
as
SessionCall
;
use
session
::
Call
as
SessionCall
;
use
version
::
RuntimeVersion
;
/// Produces the list of inherent extrinsics.
/// Produces the list of inherent extrinsics.
pub
fn
inherent_extrinsics
(
data
:
::
primitives
::
InherentData
)
->
Vec
<
UncheckedExtrinsic
>
{
pub
fn
inherent_extrinsics
(
data
:
::
primitives
::
InherentData
,
runtime_version
:
RuntimeVersion
)
->
Vec
<
UncheckedExtrinsic
>
{
let
make_inherent
=
|
function
|
UncheckedExtrinsic
::
new
(
let
make_inherent
=
|
function
|
UncheckedExtrinsic
::
new
(
Extrinsic
{
Extrinsic
{
signed
:
Default
::
default
(),
signed
:
Default
::
default
(),
...
@@ -39,7 +40,7 @@ pub fn inherent_extrinsics(data: ::primitives::InherentData) -> Vec<UncheckedExt
...
@@ -39,7 +40,7 @@ pub fn inherent_extrinsics(data: ::primitives::InherentData) -> Vec<UncheckedExt
make_inherent
(
Call
::
Parachains
(
ParachainsCall
::
set_heads
(
data
.parachain_heads
))),
make_inherent
(
Call
::
Parachains
(
ParachainsCall
::
set_heads
(
data
.parachain_heads
))),
];
];
if
!
data
.offline_indices
.is_empty
()
{
if
!
data
.offline_indices
.is_empty
()
&&
runtime_version
.spec_version
==
4
{
inherent
.push
(
make_inherent
(
inherent
.push
(
make_inherent
(
Call
::
Session
(
SessionCall
::
note_offline
(
data
.offline_indices
))
Call
::
Session
(
SessionCall
::
note_offline
(
data
.offline_indices
))
));
));
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment