fix(solc): consistent serde for linked and unlinked bytecode (#948)
This commit is contained in:
parent
1f822e47e6
commit
60515d9404
|
@ -1592,6 +1592,7 @@ pub enum BytecodeObject {
|
||||||
#[serde(deserialize_with = "serde_helpers::deserialize_bytes")]
|
#[serde(deserialize_with = "serde_helpers::deserialize_bytes")]
|
||||||
Bytecode(Bytes),
|
Bytecode(Bytes),
|
||||||
/// Bytecode as hex string that's not fully linked yet and contains library placeholders
|
/// Bytecode as hex string that's not fully linked yet and contains library placeholders
|
||||||
|
#[serde(with = "serde_helpers::string_bytes")]
|
||||||
Unlinked(String),
|
Unlinked(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1612,6 +1613,13 @@ impl BytecodeObject {
|
||||||
BytecodeObject::Unlinked(_) => None,
|
BytecodeObject::Unlinked(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Returns a reference to the underlying `String` if the object is unlinked
|
||||||
|
pub fn as_str(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
BytecodeObject::Bytecode(_) => None,
|
||||||
|
BytecodeObject::Unlinked(s) => Some(s.as_str()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the unlinked `String` if the object is unlinked or empty
|
/// Returns the unlinked `String` if the object is unlinked or empty
|
||||||
pub fn into_unlinked(self) -> Option<String> {
|
pub fn into_unlinked(self) -> Option<String> {
|
||||||
|
@ -1715,10 +1723,10 @@ impl BytecodeObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a not deployable bytecode by default as "0x"
|
// Returns a not deployable bytecode by default as empty
|
||||||
impl Default for BytecodeObject {
|
impl Default for BytecodeObject {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
BytecodeObject::Unlinked("0x".to_string())
|
BytecodeObject::Unlinked("".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,34 @@ pub mod json_string_opt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// serde support for string
|
||||||
|
pub mod string_bytes {
|
||||||
|
use serde::{Deserialize, Deserializer, Serializer};
|
||||||
|
|
||||||
|
pub fn serialize<S>(value: &String, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
if value.starts_with("0x") {
|
||||||
|
serializer.serialize_str(value.as_str())
|
||||||
|
} else {
|
||||||
|
serializer.serialize_str(&format!("0x{}", value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<'de, D>(deserializer: D) -> Result<String, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let value = String::deserialize(deserializer)?;
|
||||||
|
if let Some(rem) = value.strip_prefix("0x") {
|
||||||
|
Ok(rem.to_string())
|
||||||
|
} else {
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod display_from_str_opt {
|
pub mod display_from_str_opt {
|
||||||
use serde::{de, Deserialize, Deserializer, Serializer};
|
use serde::{de, Deserialize, Deserializer, Serializer};
|
||||||
use std::{fmt, str::FromStr};
|
use std::{fmt, str::FromStr};
|
||||||
|
|
|
@ -496,7 +496,7 @@ fn can_detect_type_error() {
|
||||||
fn can_compile_single_files() {
|
fn can_compile_single_files() {
|
||||||
let tmp = TempProject::dapptools().unwrap();
|
let tmp = TempProject::dapptools().unwrap();
|
||||||
|
|
||||||
let foo = tmp
|
let f = tmp
|
||||||
.add_contract(
|
.add_contract(
|
||||||
"examples/Foo",
|
"examples/Foo",
|
||||||
r#"
|
r#"
|
||||||
|
@ -507,7 +507,7 @@ fn can_compile_single_files() {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let compiled = tmp.project().compile_file(foo.clone()).unwrap();
|
let compiled = tmp.project().compile_file(f.clone()).unwrap();
|
||||||
assert!(!compiled.has_compiler_errors());
|
assert!(!compiled.has_compiler_errors());
|
||||||
assert!(compiled.find("Foo").is_some());
|
assert!(compiled.find("Foo").is_some());
|
||||||
|
|
||||||
|
@ -522,8 +522,43 @@ fn can_compile_single_files() {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let compiled = tmp.project().compile_files(vec![foo, bar]).unwrap();
|
let compiled = tmp.project().compile_files(vec![f, bar]).unwrap();
|
||||||
assert!(!compiled.has_compiler_errors());
|
assert!(!compiled.has_compiler_errors());
|
||||||
assert!(compiled.find("Foo").is_some());
|
assert!(compiled.find("Foo").is_some());
|
||||||
assert!(compiled.find("Bar").is_some());
|
assert!(compiled.find("Bar").is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn consistent_bytecode() {
|
||||||
|
let tmp = TempProject::dapptools().unwrap();
|
||||||
|
|
||||||
|
tmp.add_source(
|
||||||
|
"LinkTest",
|
||||||
|
r#"
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
library LibTest {
|
||||||
|
function foobar(uint256 a) public view returns (uint256) {
|
||||||
|
return a * 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contract LinkTest {
|
||||||
|
function foo() public returns (uint256) {
|
||||||
|
return LibTest.foobar(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let compiled = tmp.compile().unwrap();
|
||||||
|
assert!(!compiled.has_compiler_errors());
|
||||||
|
|
||||||
|
let contract = compiled.find("LinkTest").unwrap();
|
||||||
|
let bytecode = &contract.bytecode.as_ref().unwrap().object;
|
||||||
|
assert!(bytecode.is_unlinked());
|
||||||
|
let s = bytecode.as_str().unwrap();
|
||||||
|
assert!(!s.starts_with("0x"));
|
||||||
|
|
||||||
|
let s = serde_json::to_string(&bytecode).unwrap();
|
||||||
|
assert_eq!(bytecode.clone(), serde_json::from_str(&s).unwrap());
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue