mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-05-08 07:48:01 +00:00
Separate compilation and linker phases (#376)
Separate between compilation and linker phases to allow deploy time linking and back-porting era compiler changes to fix #91. Unlinked contract binaries (caused by missing libraries or missing factory dependencies in turn) are emitted as raw ELF object. Few drive by fixes: - #98 - A compiler panic on missing libraries definitions. - Fixes some incosistent type forwarding in JSON output (empty string vs. null object). - Remove the unused fallback for size optimization setting. - Remove the broken `--lvm-ir` mode. - CI workflow fixes. --------- Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com> Signed-off-by: xermicus <bigcyrill@hotmail.com> Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
@@ -1,14 +1,19 @@
|
||||
//! The `solc --standard-json` output error.
|
||||
|
||||
pub mod source_location;
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::SolcStandardJsonInputSource;
|
||||
|
||||
use self::mapped_location::MappedLocation;
|
||||
use self::source_location::SourceLocation;
|
||||
|
||||
pub mod error_handler;
|
||||
pub mod mapped_location;
|
||||
pub mod source_location;
|
||||
|
||||
/// The `solc --standard-json` output error.
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -30,29 +35,81 @@ pub struct Error {
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// Returns the `ecrecover` function usage warning.
|
||||
pub fn message_ecrecover(src: Option<&str>) -> Self {
|
||||
let message = r#"
|
||||
Warning: It looks like you are using 'ecrecover' to validate a signature of a user account.
|
||||
Polkadot comes with native account abstraction support, therefore it is highly recommended NOT
|
||||
to rely on the fact that the account has an ECDSA private key attached to it since accounts might
|
||||
implement other signature schemes.
|
||||
"#
|
||||
.to_owned();
|
||||
/// The list of ignored `solc` warnings that are strictly EVM-related.
|
||||
pub const IGNORED_WARNING_CODES: [&'static str; 5] = ["1699", "3860", "5159", "5574", "6417"];
|
||||
|
||||
/// A shortcut constructor.
|
||||
pub fn new<S>(
|
||||
r#type: &str,
|
||||
message: S,
|
||||
source_location: Option<SourceLocation>,
|
||||
sources: Option<&BTreeMap<String, SolcStandardJsonInputSource>>,
|
||||
) -> Self
|
||||
where
|
||||
S: std::fmt::Display,
|
||||
{
|
||||
let message = message.to_string();
|
||||
|
||||
let message_trimmed = message.trim();
|
||||
let mut formatted_message = if message_trimmed.starts_with(r#type) {
|
||||
message_trimmed.to_owned()
|
||||
} else {
|
||||
format!("{type}: {message_trimmed}")
|
||||
};
|
||||
formatted_message.push('\n');
|
||||
if let Some(ref source_location) = source_location {
|
||||
let source_code = sources.and_then(|sources| {
|
||||
sources
|
||||
.get(source_location.file.as_str())
|
||||
.and_then(|source| source.content())
|
||||
});
|
||||
let mapped_location =
|
||||
MappedLocation::try_from_source_location(source_location, source_code);
|
||||
formatted_message.push_str(mapped_location.to_string().as_str());
|
||||
formatted_message.push('\n');
|
||||
}
|
||||
|
||||
Self {
|
||||
component: "general".to_owned(),
|
||||
error_code: None,
|
||||
formatted_message: message.clone(),
|
||||
formatted_message,
|
||||
message,
|
||||
severity: "warning".to_owned(),
|
||||
source_location: src.map(SourceLocation::from_str).and_then(Result::ok),
|
||||
r#type: "Warning".to_owned(),
|
||||
severity: r#type.to_lowercase(),
|
||||
source_location,
|
||||
r#type: r#type.to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
/// A shortcut constructor.
|
||||
pub fn new_error<S>(
|
||||
message: S,
|
||||
source_location: Option<SourceLocation>,
|
||||
sources: Option<&BTreeMap<String, SolcStandardJsonInputSource>>,
|
||||
) -> Self
|
||||
where
|
||||
S: std::fmt::Display,
|
||||
{
|
||||
Self::new("Error", message, source_location, sources)
|
||||
}
|
||||
|
||||
/// A shortcut constructor.
|
||||
pub fn new_warning<S>(
|
||||
message: S,
|
||||
source_location: Option<SourceLocation>,
|
||||
sources: Option<&BTreeMap<String, SolcStandardJsonInputSource>>,
|
||||
) -> Self
|
||||
where
|
||||
S: std::fmt::Display,
|
||||
{
|
||||
Self::new("Warning", message, source_location, sources)
|
||||
}
|
||||
|
||||
/// Returns the `<address payable>`'s `send` and `transfer` methods usage error.
|
||||
pub fn message_send_and_transfer(src: Option<&str>) -> Self {
|
||||
pub fn warning_send_and_transfer(
|
||||
node: Option<&str>,
|
||||
id_paths: &BTreeMap<usize, &String>,
|
||||
sources: &BTreeMap<String, SolcStandardJsonInputSource>,
|
||||
) -> Self {
|
||||
let message = r#"
|
||||
Warning: It looks like you are using '<address payable>.send/transfer(<X>)'.
|
||||
Using '<address payable>.send/transfer(<X>)' is deprecated and strongly discouraged!
|
||||
@@ -65,43 +122,19 @@ and https://docs.soliditylang.org/en/latest/common-patterns.html#withdrawal-from
|
||||
"#
|
||||
.to_owned();
|
||||
|
||||
Self {
|
||||
component: "general".to_owned(),
|
||||
error_code: None,
|
||||
formatted_message: message.clone(),
|
||||
Self::new_warning(
|
||||
message,
|
||||
severity: "warning".to_owned(),
|
||||
source_location: src.map(SourceLocation::from_str).and_then(Result::ok),
|
||||
r#type: "Warning".to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `extcodesize` instruction usage warning.
|
||||
pub fn message_extcodesize(src: Option<&str>) -> Self {
|
||||
let message = r#"
|
||||
Warning: Your code or one of its dependencies uses the 'extcodesize' instruction, which is
|
||||
usually needed in the following cases:
|
||||
1. To detect whether an address belongs to a smart contract.
|
||||
2. To detect whether the deploy code execution has finished.
|
||||
Polkadot comes with native account abstraction support (so smart contracts are just accounts
|
||||
coverned by code), and you should avoid differentiating between contracts and non-contract
|
||||
addresses.
|
||||
"#
|
||||
.to_owned();
|
||||
|
||||
Self {
|
||||
component: "general".to_owned(),
|
||||
error_code: None,
|
||||
formatted_message: message.clone(),
|
||||
message,
|
||||
severity: "warning".to_owned(),
|
||||
source_location: src.map(SourceLocation::from_str).and_then(Result::ok),
|
||||
r#type: "Warning".to_owned(),
|
||||
}
|
||||
node.and_then(|node| SourceLocation::try_from_ast(node, id_paths)),
|
||||
Some(sources),
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the `origin` instruction usage warning.
|
||||
pub fn message_tx_origin(src: Option<&str>) -> Self {
|
||||
pub fn warning_tx_origin(
|
||||
node: Option<&str>,
|
||||
id_paths: &BTreeMap<usize, &String>,
|
||||
sources: &BTreeMap<String, SolcStandardJsonInputSource>,
|
||||
) -> Self {
|
||||
let message = r#"
|
||||
Warning: You are checking for 'tx.origin' in your code, which might lead to unexpected behavior.
|
||||
Polkadot comes with native account abstraction support, and therefore the initiator of a
|
||||
@@ -110,15 +143,28 @@ to rely on tx.origin, but use msg.sender instead.
|
||||
"#
|
||||
.to_owned();
|
||||
|
||||
Self {
|
||||
component: "general".to_owned(),
|
||||
error_code: None,
|
||||
formatted_message: message.clone(),
|
||||
Self::new_warning(
|
||||
message,
|
||||
severity: "warning".to_owned(),
|
||||
source_location: src.map(SourceLocation::from_str).and_then(Result::ok),
|
||||
r#type: "Warning".to_owned(),
|
||||
}
|
||||
node.and_then(|node| SourceLocation::try_from_ast(node, id_paths)),
|
||||
Some(sources),
|
||||
)
|
||||
}
|
||||
/// Returns the `runtimeCode` code usage error.
|
||||
pub fn error_runtime_code(
|
||||
node: Option<&str>,
|
||||
id_paths: &BTreeMap<usize, &String>,
|
||||
sources: &BTreeMap<String, SolcStandardJsonInputSource>,
|
||||
) -> Self {
|
||||
let message = r#"
|
||||
Deploy and runtime code are merged in PVM, accessing `type(T).runtimeCode` is not possible.
|
||||
Please consider changing the functionality relying on reading runtime code to a different approach.
|
||||
"#;
|
||||
|
||||
Self::new_error(
|
||||
message,
|
||||
node.and_then(|node| SourceLocation::try_from_ast(node, id_paths)),
|
||||
Some(sources),
|
||||
)
|
||||
}
|
||||
|
||||
/// Appends the contract path to the message..
|
||||
@@ -126,6 +172,16 @@ to rely on tx.origin, but use msg.sender instead.
|
||||
self.formatted_message
|
||||
.push_str(format!("\n--> {path}\n").as_str());
|
||||
}
|
||||
|
||||
/// Returns true if this is an error.
|
||||
pub fn is_error(&self) -> bool {
|
||||
self.severity == "error"
|
||||
}
|
||||
|
||||
/// Returns true if this is a warning.
|
||||
pub fn is_warning(&self) -> bool {
|
||||
self.severity == "warning"
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
|
||||
Reference in New Issue
Block a user