fix (light/provider) : Make read_only executions
read-only (#9591)
* `ExecutionsRequest` from light-clients as read-only This changes so all `ExecutionRequests` from light-clients are executed as read-only which the `virtual``flag == true ensures. This boost up the current transaction to always succeed Note, this only affects `eth_estimateGas` and `eth_call` AFAIK. * grumbles(revert renaming) : TransactionProof * grumbles(trace) : remove incorrect trace * grumbles(state/prove_tx) : explicit `virt` Remove the boolean flag to determine that a `state::prove_transaction` whether it should be executed in a virtual context or not. Because of that also rename the function to `state::prove_transction_virtual` to make more clear
This commit is contained in:
parent
dc14cce7a9
commit
5b54442a48
@ -2381,14 +2381,13 @@ impl ProvingBlockChainClient for Client {
|
|||||||
env_info.gas_limit = transaction.gas.clone();
|
env_info.gas_limit = transaction.gas.clone();
|
||||||
let mut jdb = self.state_db.read().journal_db().boxed_clone();
|
let mut jdb = self.state_db.read().journal_db().boxed_clone();
|
||||||
|
|
||||||
state::prove_transaction(
|
state::prove_transaction_virtual(
|
||||||
jdb.as_hashdb_mut(),
|
jdb.as_hashdb_mut(),
|
||||||
header.state_root().clone(),
|
header.state_root().clone(),
|
||||||
&transaction,
|
&transaction,
|
||||||
self.engine.machine(),
|
self.engine.machine(),
|
||||||
&env_info,
|
&env_info,
|
||||||
self.factories.clone(),
|
self.factories.clone(),
|
||||||
false,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -877,14 +877,13 @@ impl Spec {
|
|||||||
data: d,
|
data: d,
|
||||||
}.fake_sign(from);
|
}.fake_sign(from);
|
||||||
|
|
||||||
let res = ::state::prove_transaction(
|
let res = ::state::prove_transaction_virtual(
|
||||||
db.as_hashdb_mut(),
|
db.as_hashdb_mut(),
|
||||||
*genesis.state_root(),
|
*genesis.state_root(),
|
||||||
&tx,
|
&tx,
|
||||||
self.engine.machine(),
|
self.engine.machine(),
|
||||||
&env_info,
|
&env_info,
|
||||||
factories.clone(),
|
factories.clone(),
|
||||||
true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
res.map(|(out, proof)| {
|
res.map(|(out, proof)| {
|
||||||
|
@ -224,17 +224,16 @@ pub fn check_proof(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prove a transaction on the given state.
|
/// Prove a `virtual` transaction on the given state.
|
||||||
/// Returns `None` when the transacion could not be proved,
|
/// Returns `None` when the transacion could not be proved,
|
||||||
/// and a proof otherwise.
|
/// and a proof otherwise.
|
||||||
pub fn prove_transaction<H: AsHashDB<KeccakHasher> + Send + Sync>(
|
pub fn prove_transaction_virtual<H: AsHashDB<KeccakHasher> + Send + Sync>(
|
||||||
db: H,
|
db: H,
|
||||||
root: H256,
|
root: H256,
|
||||||
transaction: &SignedTransaction,
|
transaction: &SignedTransaction,
|
||||||
machine: &Machine,
|
machine: &Machine,
|
||||||
env_info: &EnvInfo,
|
env_info: &EnvInfo,
|
||||||
factories: Factories,
|
factories: Factories,
|
||||||
virt: bool,
|
|
||||||
) -> Option<(Bytes, Vec<DBValue>)> {
|
) -> Option<(Bytes, Vec<DBValue>)> {
|
||||||
use self::backend::Proving;
|
use self::backend::Proving;
|
||||||
|
|
||||||
@ -252,7 +251,7 @@ pub fn prove_transaction<H: AsHashDB<KeccakHasher> + Send + Sync>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let options = TransactOptions::with_no_tracing().dont_check_nonce().save_output_from_contract();
|
let options = TransactOptions::with_no_tracing().dont_check_nonce().save_output_from_contract();
|
||||||
match state.execute(env_info, machine, transaction, options, virt) {
|
match state.execute(env_info, machine, transaction, options, true) {
|
||||||
Err(ExecutionError::Internal(_)) => None,
|
Err(ExecutionError::Internal(_)) => None,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
trace!(target: "state", "Proved call failed: {}", e);
|
trace!(target: "state", "Proved call failed: {}", e);
|
||||||
|
@ -191,7 +191,7 @@ impl LightFetch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Helper for getting proved execution.
|
/// Helper for getting proved execution.
|
||||||
pub fn proved_execution(&self, req: CallRequest, num: Trailing<BlockNumber>) -> impl Future<Item = ExecutionResult, Error = Error> + Send {
|
pub fn proved_read_only_execution(&self, req: CallRequest, num: Trailing<BlockNumber>) -> impl Future<Item = ExecutionResult, Error = Error> + Send {
|
||||||
const DEFAULT_GAS_PRICE: u64 = 21_000;
|
const DEFAULT_GAS_PRICE: u64 = 21_000;
|
||||||
// starting gas when gas not provided.
|
// starting gas when gas not provided.
|
||||||
const START_GAS: u64 = 50_000;
|
const START_GAS: u64 = 50_000;
|
||||||
@ -256,14 +256,14 @@ impl LightFetch {
|
|||||||
_ => return Either::A(future::err(errors::unknown_block())),
|
_ => return Either::A(future::err(errors::unknown_block())),
|
||||||
};
|
};
|
||||||
|
|
||||||
Either::B(execute_tx(gas_known, ExecuteParams {
|
Either::B(execute_read_only_tx(gas_known, ExecuteParams {
|
||||||
from: from,
|
from,
|
||||||
tx: tx,
|
tx,
|
||||||
hdr: hdr,
|
hdr,
|
||||||
env_info: env_info,
|
env_info,
|
||||||
engine: client.engine().clone(),
|
engine: client.engine().clone(),
|
||||||
on_demand: on_demand,
|
on_demand,
|
||||||
sync: sync,
|
sync,
|
||||||
}))
|
}))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -608,10 +608,10 @@ struct ExecuteParams {
|
|||||||
|
|
||||||
// has a peer execute the transaction with given params. If `gas_known` is false,
|
// has a peer execute the transaction with given params. If `gas_known` is false,
|
||||||
// this will double the gas on each `OutOfGas` error.
|
// this will double the gas on each `OutOfGas` error.
|
||||||
fn execute_tx(gas_known: bool, params: ExecuteParams) -> impl Future<Item = ExecutionResult, Error = Error> + Send {
|
fn execute_read_only_tx(gas_known: bool, params: ExecuteParams) -> impl Future<Item = ExecutionResult, Error = Error> + Send {
|
||||||
if !gas_known {
|
if !gas_known {
|
||||||
Box::new(future::loop_fn(params, |mut params| {
|
Box::new(future::loop_fn(params, |mut params| {
|
||||||
execute_tx(true, params.clone()).and_then(move |res| {
|
execute_read_only_tx(true, params.clone()).and_then(move |res| {
|
||||||
match res {
|
match res {
|
||||||
Ok(executed) => {
|
Ok(executed) => {
|
||||||
// TODO: how to distinguish between actual OOG and
|
// TODO: how to distinguish between actual OOG and
|
||||||
|
@ -381,7 +381,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, req: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<Bytes> {
|
fn call(&self, req: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<Bytes> {
|
||||||
Box::new(self.fetcher().proved_execution(req, num).and_then(|res| {
|
Box::new(self.fetcher().proved_read_only_execution(req, num).and_then(|res| {
|
||||||
match res {
|
match res {
|
||||||
Ok(exec) => Ok(exec.output.into()),
|
Ok(exec) => Ok(exec.output.into()),
|
||||||
Err(e) => Err(errors::execution(e)),
|
Err(e) => Err(errors::execution(e)),
|
||||||
@ -391,7 +391,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
|
|||||||
|
|
||||||
fn estimate_gas(&self, req: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256> {
|
fn estimate_gas(&self, req: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256> {
|
||||||
// TODO: binary chop for more accurate estimates.
|
// TODO: binary chop for more accurate estimates.
|
||||||
Box::new(self.fetcher().proved_execution(req, num).and_then(|res| {
|
Box::new(self.fetcher().proved_read_only_execution(req, num).and_then(|res| {
|
||||||
match res {
|
match res {
|
||||||
Ok(exec) => Ok((exec.refunded + exec.gas_used).into()),
|
Ok(exec) => Ok((exec.refunded + exec.gas_used).into()),
|
||||||
Err(e) => Err(errors::execution(e)),
|
Err(e) => Err(errors::execution(e)),
|
||||||
|
Loading…
Reference in New Issue
Block a user