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:
Niklas Adolfsson 2018-10-08 21:30:46 +02:00 committed by GitHub
parent dc14cce7a9
commit 5b54442a48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 17 additions and 20 deletions

View File

@ -2381,14 +2381,13 @@ impl ProvingBlockChainClient for Client {
env_info.gas_limit = transaction.gas.clone();
let mut jdb = self.state_db.read().journal_db().boxed_clone();
state::prove_transaction(
state::prove_transaction_virtual(
jdb.as_hashdb_mut(),
header.state_root().clone(),
&transaction,
self.engine.machine(),
&env_info,
self.factories.clone(),
false,
)
}

View File

@ -877,14 +877,13 @@ impl Spec {
data: d,
}.fake_sign(from);
let res = ::state::prove_transaction(
let res = ::state::prove_transaction_virtual(
db.as_hashdb_mut(),
*genesis.state_root(),
&tx,
self.engine.machine(),
&env_info,
factories.clone(),
true,
);
res.map(|(out, proof)| {

View File

@ -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,
/// 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,
root: H256,
transaction: &SignedTransaction,
machine: &Machine,
env_info: &EnvInfo,
factories: Factories,
virt: bool,
) -> Option<(Bytes, Vec<DBValue>)> {
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();
match state.execute(env_info, machine, transaction, options, virt) {
match state.execute(env_info, machine, transaction, options, true) {
Err(ExecutionError::Internal(_)) => None,
Err(e) => {
trace!(target: "state", "Proved call failed: {}", e);

View File

@ -191,7 +191,7 @@ impl LightFetch {
}
/// 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;
// starting gas when gas not provided.
const START_GAS: u64 = 50_000;
@ -256,14 +256,14 @@ impl LightFetch {
_ => return Either::A(future::err(errors::unknown_block())),
};
Either::B(execute_tx(gas_known, ExecuteParams {
from: from,
tx: tx,
hdr: hdr,
env_info: env_info,
Either::B(execute_read_only_tx(gas_known, ExecuteParams {
from,
tx,
hdr,
env_info,
engine: client.engine().clone(),
on_demand: on_demand,
sync: sync,
on_demand,
sync,
}))
}))
}
@ -608,10 +608,10 @@ struct ExecuteParams {
// has a peer execute the transaction with given params. If `gas_known` is false,
// 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 {
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 {
Ok(executed) => {
// TODO: how to distinguish between actual OOG and

View File

@ -381,7 +381,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
}
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 {
Ok(exec) => Ok(exec.output.into()),
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> {
// 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 {
Ok(exec) => Ok((exec.refunded + exec.gas_used).into()),
Err(e) => Err(errors::execution(e)),