mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-12 14:41:11 +00:00
contracts: Allow indeterministic instructions off-chain (#12469)
* Allow indetermistic instructions off-chain * Apply suggestions from code review Co-authored-by: Sasha Gryaznov <hi@agryaznov.com> * fmt Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>
This commit is contained in:
committed by
GitHub
parent
d0dcf008ec
commit
3ae4be8662
@@ -18,7 +18,7 @@
|
||||
use crate::{
|
||||
gas::GasMeter,
|
||||
storage::{self, Storage, WriteOutcome},
|
||||
BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, Error, Event, Nonce,
|
||||
BalanceOf, CodeHash, Config, ContractInfo, ContractInfoOf, Determinism, Error, Event, Nonce,
|
||||
Pallet as Contracts, Schedule,
|
||||
};
|
||||
use frame_support::{
|
||||
@@ -355,6 +355,9 @@ pub trait Executable<T: Config>: Sized {
|
||||
|
||||
/// Size of the instrumented code in bytes.
|
||||
fn code_len(&self) -> u32;
|
||||
|
||||
/// The code does not contain any instructions which could lead to indeterminism.
|
||||
fn is_deterministic(&self) -> bool;
|
||||
}
|
||||
|
||||
/// The complete call stack of a contract execution.
|
||||
@@ -395,6 +398,8 @@ pub struct Stack<'a, T: Config, E> {
|
||||
/// All the bytes added to this field should be valid UTF-8. The buffer has no defined
|
||||
/// structure and is intended to be shown to users as-is for debugging purposes.
|
||||
debug_message: Option<&'a mut Vec<u8>>,
|
||||
/// The determinism requirement of this call stack.
|
||||
determinism: Determinism,
|
||||
/// No executable is held by the struct but influences its behaviour.
|
||||
_phantom: PhantomData<E>,
|
||||
}
|
||||
@@ -601,6 +606,7 @@ where
|
||||
value: BalanceOf<T>,
|
||||
input_data: Vec<u8>,
|
||||
debug_message: Option<&'a mut Vec<u8>>,
|
||||
determinism: Determinism,
|
||||
) -> Result<ExecReturnValue, ExecError> {
|
||||
let (mut stack, executable) = Self::new(
|
||||
FrameArgs::Call { dest, cached_info: None, delegated_call: None },
|
||||
@@ -610,6 +616,7 @@ where
|
||||
schedule,
|
||||
value,
|
||||
debug_message,
|
||||
determinism,
|
||||
)?;
|
||||
stack.run(executable, input_data)
|
||||
}
|
||||
@@ -648,6 +655,7 @@ where
|
||||
schedule,
|
||||
value,
|
||||
debug_message,
|
||||
Determinism::Deterministic,
|
||||
)?;
|
||||
let account_id = stack.top_frame().account_id.clone();
|
||||
stack.run(executable, input_data).map(|ret| (account_id, ret))
|
||||
@@ -662,9 +670,17 @@ where
|
||||
schedule: &'a Schedule<T>,
|
||||
value: BalanceOf<T>,
|
||||
debug_message: Option<&'a mut Vec<u8>>,
|
||||
determinism: Determinism,
|
||||
) -> Result<(Self, E), ExecError> {
|
||||
let (first_frame, executable, nonce) =
|
||||
Self::new_frame(args, value, gas_meter, storage_meter, Weight::zero(), schedule)?;
|
||||
let (first_frame, executable, nonce) = Self::new_frame(
|
||||
args,
|
||||
value,
|
||||
gas_meter,
|
||||
storage_meter,
|
||||
Weight::zero(),
|
||||
schedule,
|
||||
determinism,
|
||||
)?;
|
||||
let stack = Self {
|
||||
origin,
|
||||
schedule,
|
||||
@@ -676,6 +692,7 @@ where
|
||||
first_frame,
|
||||
frames: Default::default(),
|
||||
debug_message,
|
||||
determinism,
|
||||
_phantom: Default::default(),
|
||||
};
|
||||
|
||||
@@ -693,6 +710,7 @@ where
|
||||
storage_meter: &mut storage::meter::GenericMeter<T, S>,
|
||||
gas_limit: Weight,
|
||||
schedule: &Schedule<T>,
|
||||
determinism: Determinism,
|
||||
) -> Result<(Frame<T>, E, Option<u64>), ExecError> {
|
||||
let (account_id, contract_info, executable, delegate_caller, entry_point, nonce) =
|
||||
match frame_args {
|
||||
@@ -729,6 +747,15 @@ where
|
||||
},
|
||||
};
|
||||
|
||||
// `AllowIndeterminism` will only be ever set in case of off-chain execution.
|
||||
// Instantiations are never allowed even when executing off-chain.
|
||||
if !(executable.is_deterministic() ||
|
||||
(matches!(determinism, Determinism::AllowIndeterminism) &&
|
||||
matches!(entry_point, ExportedFunction::Call)))
|
||||
{
|
||||
return Err(Error::<T>::Indeterministic.into())
|
||||
}
|
||||
|
||||
let frame = Frame {
|
||||
delegate_caller,
|
||||
value_transferred,
|
||||
@@ -775,6 +802,7 @@ where
|
||||
nested_storage,
|
||||
gas_limit,
|
||||
self.schedule,
|
||||
self.determinism,
|
||||
)?;
|
||||
self.frames.push(frame);
|
||||
Ok(executable)
|
||||
@@ -1328,15 +1356,18 @@ where
|
||||
}
|
||||
|
||||
fn set_code_hash(&mut self, hash: CodeHash<Self::T>) -> Result<(), DispatchError> {
|
||||
let frame = top_frame_mut!(self);
|
||||
if !E::from_storage(hash, self.schedule, &mut frame.nested_gas)?.is_deterministic() {
|
||||
return Err(<Error<T>>::Indeterministic.into())
|
||||
}
|
||||
E::add_user(hash)?;
|
||||
let top_frame = self.top_frame_mut();
|
||||
let prev_hash = top_frame.contract_info().code_hash;
|
||||
let prev_hash = frame.contract_info().code_hash;
|
||||
E::remove_user(prev_hash);
|
||||
top_frame.contract_info().code_hash = hash;
|
||||
frame.contract_info().code_hash = hash;
|
||||
Contracts::<Self::T>::deposit_event(
|
||||
vec![T::Hashing::hash_of(&top_frame.account_id), hash, prev_hash],
|
||||
vec![T::Hashing::hash_of(&frame.account_id), hash, prev_hash],
|
||||
Event::ContractCodeUpdated {
|
||||
contract: top_frame.account_id.clone(),
|
||||
contract: frame.account_id.clone(),
|
||||
new_code_hash: hash,
|
||||
old_code_hash: prev_hash,
|
||||
},
|
||||
@@ -1513,6 +1544,10 @@ mod tests {
|
||||
fn code_len(&self) -> u32 {
|
||||
0
|
||||
}
|
||||
|
||||
fn is_deterministic(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn exec_success() -> ExecResult {
|
||||
@@ -1551,6 +1586,7 @@ mod tests {
|
||||
value,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
),
|
||||
Ok(_)
|
||||
);
|
||||
@@ -1604,6 +1640,7 @@ mod tests {
|
||||
value,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -1645,6 +1682,7 @@ mod tests {
|
||||
value,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -1680,6 +1718,7 @@ mod tests {
|
||||
55,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -1731,6 +1770,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
|
||||
let output = result.unwrap();
|
||||
@@ -1763,6 +1803,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
|
||||
let output = result.unwrap();
|
||||
@@ -1793,6 +1834,7 @@ mod tests {
|
||||
0,
|
||||
vec![1, 2, 3, 4],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
@@ -1873,6 +1915,7 @@ mod tests {
|
||||
value,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
|
||||
assert_matches!(result, Ok(_));
|
||||
@@ -1918,6 +1961,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
|
||||
assert_matches!(result, Ok(_));
|
||||
@@ -1951,6 +1995,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
@@ -1980,6 +2025,7 @@ mod tests {
|
||||
0,
|
||||
vec![0],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
@@ -2007,6 +2053,7 @@ mod tests {
|
||||
0,
|
||||
vec![0],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
@@ -2042,6 +2089,7 @@ mod tests {
|
||||
0,
|
||||
vec![0],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
@@ -2077,6 +2125,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
|
||||
assert_matches!(result, Ok(_));
|
||||
@@ -2235,6 +2284,7 @@ mod tests {
|
||||
min_balance * 10,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
),
|
||||
Ok(_)
|
||||
);
|
||||
@@ -2299,6 +2349,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
),
|
||||
Ok(_)
|
||||
);
|
||||
@@ -2384,6 +2435,7 @@ mod tests {
|
||||
0,
|
||||
vec![0],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
@@ -2450,6 +2502,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
Some(&mut debug_buffer),
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.unwrap();
|
||||
});
|
||||
@@ -2483,6 +2536,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
Some(&mut debug_buffer),
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert!(result.is_err());
|
||||
});
|
||||
@@ -2516,6 +2570,7 @@ mod tests {
|
||||
0,
|
||||
CHARLIE.encode(),
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
));
|
||||
|
||||
// Calling into oneself fails
|
||||
@@ -2529,6 +2584,7 @@ mod tests {
|
||||
0,
|
||||
BOB.encode(),
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
)
|
||||
.map_err(|e| e.error),
|
||||
<Error<Test>>::ReentranceDenied,
|
||||
@@ -2567,6 +2623,7 @@ mod tests {
|
||||
0,
|
||||
vec![0],
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
)
|
||||
.map_err(|e| e.error),
|
||||
<Error<Test>>::ReentranceDenied,
|
||||
@@ -2601,6 +2658,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -2683,6 +2741,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -2886,6 +2945,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
));
|
||||
});
|
||||
}
|
||||
@@ -3012,6 +3072,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
));
|
||||
});
|
||||
}
|
||||
@@ -3047,6 +3108,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
));
|
||||
});
|
||||
}
|
||||
@@ -3082,6 +3144,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
));
|
||||
});
|
||||
}
|
||||
@@ -3143,6 +3206,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
));
|
||||
});
|
||||
}
|
||||
@@ -3204,6 +3268,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic
|
||||
));
|
||||
});
|
||||
}
|
||||
@@ -3235,6 +3300,7 @@ mod tests {
|
||||
0,
|
||||
vec![],
|
||||
None,
|
||||
Determinism::Deterministic,
|
||||
);
|
||||
assert_matches!(result, Ok(_));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user