Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Storage operations refactor. #251

Merged
merged 1 commit into from Feb 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions analyzer/src/namespace/events.rs
Expand Up @@ -2,7 +2,7 @@ use crate::namespace::types::{
AbiEncoding,
FixedSize,
};
use fe_common::utils::keccak::get_full_signature;
use fe_common::utils::keccak;

#[derive(Clone, Debug, PartialEq)]
pub struct Event {
Expand Down Expand Up @@ -64,7 +64,7 @@ impl Event {

fn build_event_topic(name: &str, fields: Vec<String>) -> String {
let signature = format!("{}({})", name, fields.join(","));
get_full_signature(signature.as_bytes())
keccak::full(signature.as_bytes())
}

#[cfg(test)]
Expand Down
8 changes: 3 additions & 5 deletions analyzer/src/namespace/types.rs
Expand Up @@ -13,8 +13,6 @@ use std::num::{
use crate::FunctionAttributes;
use num_bigint::BigInt;

const ADDRESS_BYTE_LENGTH: usize = 20;

pub fn u256_max() -> BigInt {
BigInt::from(2).pow(256) - 1
}
Expand Down Expand Up @@ -422,7 +420,7 @@ impl FeSized for Base {
Base::Numeric(integer) => integer.size(),
Base::Bool => 1,
Base::Byte => 1,
Base::Address => ADDRESS_BYTE_LENGTH,
Base::Address => 32,
}
}
}
Expand Down Expand Up @@ -536,7 +534,7 @@ impl AbiEncoding for Base {
},
Base::Address => AbiType::Uint {
size: AbiUintSize {
data_size: ADDRESS_BYTE_LENGTH,
data_size: 32,
padded_size: 32,
},
},
Expand Down Expand Up @@ -669,7 +667,7 @@ impl AbiEncoding for FeString {

impl FeSized for Contract {
fn size(&self) -> usize {
ADDRESS_BYTE_LENGTH
32
}
}

Expand Down
32 changes: 24 additions & 8 deletions common/src/utils/keccak.rs
Expand Up @@ -3,12 +3,32 @@ use tiny_keccak::{
Keccak,
};

pub fn get_full_signature(content: &[u8]) -> String {
get_partial_signature(content, 32)
/// Get the full 32 byte hash of the content.
pub fn full(content: &[u8]) -> String {
partial(content, 32)
}

/// Return the keccak256 hash of the given content as an array of bytes
pub fn get_keccak256(content: &[u8]) -> [u8; 32] {
/// Take the first `size` number of bytes of the hash and pad the right side
/// with zeros to 32 bytes.
pub fn partial_right_padded(content: &[u8], size: usize) -> String {
let result = full_as_bytes(content);
let padded_output: Vec<u8> = result
.iter()
.enumerate()
.map(|(index, byte)| if index >= size { 0 } else { *byte })
.collect();

format!("0x{}", hex::encode(&padded_output))
}

/// Take the first `size` number of bytes of the hash with no padding.
pub fn partial(content: &[u8], size: usize) -> String {
let result = full_as_bytes(content);
format!("0x{}", hex::encode(&result[0..size]))
}

/// Get the full 32 byte hash of the content as a byte array.
pub fn full_as_bytes(content: &[u8]) -> [u8; 32] {
let mut keccak = Keccak::v256();
let mut selector = [0u8; 32];

Expand All @@ -17,7 +37,3 @@ pub fn get_keccak256(content: &[u8]) -> [u8; 32] {

selector
}

pub fn get_partial_signature(content: &[u8], size: usize) -> String {
format!("0x{}", hex::encode(&get_keccak256(content)[0..size]))
}
4 changes: 2 additions & 2 deletions compiler/src/abi/utils.rs
@@ -1,4 +1,4 @@
use fe_common::utils::keccak::get_partial_signature;
use fe_common::utils::keccak;

/// Formats the name and fields and calculates the 32 byte keccak256 value of
/// the signature.
Expand All @@ -13,5 +13,5 @@ pub fn func_selector(name: &str, params: Vec<String>) -> String {

fn sign_event_or_func(name: &str, params: Vec<String>, size: usize) -> String {
let signature = format!("{}({})", name, params.join(","));
get_partial_signature(signature.as_bytes(), size)
keccak::partial(signature.as_bytes(), size)
}
2 changes: 1 addition & 1 deletion compiler/src/yul/mappers/assignments.rs
Expand Up @@ -177,7 +177,7 @@ mod tests {

assert_eq!(
map(&harness.context, &harness.src),
"mstoren(add($foo, mul(4, 32)), 2, 32)"
"mstoren(add($foo, mul(4, 32)), 32, 2)"
)
}
}
4 changes: 2 additions & 2 deletions compiler/src/yul/mappers/contracts.rs
Expand Up @@ -3,7 +3,7 @@ use crate::yul::constructor;
use crate::yul::mappers::functions;
use crate::yul::runtime;
use fe_analyzer::Context;
use fe_common::utils::keccak::get_full_signature;
use fe_common::utils::keccak;
use fe_parser::ast as fe;
use fe_parser::span::Spanned;
use yultsur::*;
Expand Down Expand Up @@ -53,7 +53,7 @@ pub fn contract_def(
.clone()
.into_iter()
.map(|val| yul::Data {
name: get_full_signature(val.as_bytes()),
name: keccak::full(val.as_bytes()),
value: val,
})
.collect::<Vec<_>>()
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/yul/mappers/declarations.rs
Expand Up @@ -91,7 +91,7 @@ mod tests {

assert_eq!(
map(&harness.context, &harness.src),
"let $foo := alloc(200)"
"let $foo := alloc(320)"
g-r-a-n-t marked this conversation as resolved.
Show resolved Hide resolved
);
}
}
17 changes: 10 additions & 7 deletions compiler/src/yul/mappers/expressions.rs
Expand Up @@ -24,7 +24,7 @@ use fe_analyzer::{
Context,
g-r-a-n-t marked this conversation as resolved.
Show resolved Hide resolved
Location,
};
use fe_common::utils::keccak::get_full_signature;
use fe_common::utils::keccak;
use fe_parser::ast as fe;
use fe_parser::span::Spanned;
use std::convert::TryFrom;
Expand Down Expand Up @@ -339,7 +339,7 @@ fn expr_bool(exp: &Spanned<fe::Expr>) -> Result<yul::Expression, CompileError> {
fn expr_str(exp: &Spanned<fe::Expr>) -> Result<yul::Expression, CompileError> {
if let fe::Expr::Str(lines) = &exp.node {
let content = lines.join("");
let string_identifier = format!(r#""{}""#, get_full_signature(content.as_bytes()));
let string_identifier = format!(r#""{}""#, keccak::full(content.as_bytes()));

let offset = expression! { dataoffset([literal_expression! { (string_identifier) }]) };
let size = expression! { datasize([literal_expression! { (string_identifier) }]) };
Expand Down Expand Up @@ -475,15 +475,18 @@ fn expr_attribute_self(
}

/// Converts a storage nonce into a pointer based on the keccak256 hash
///
/// Pointers created here have the last byte set to zero. This is to ensure that
/// our byte pointer sits at the start of a word (32 | `ptr` ).
pub fn nonce_to_ptr(nonce: usize) -> yul::Expression {
let ptr = get_full_signature(nonce.to_string().as_bytes());
// set the last byte to `0x00` to ensure our pointer sits at the start of a word
g-r-a-n-t marked this conversation as resolved.
Show resolved Hide resolved
let ptr = keccak::partial_right_padded(nonce.to_string().as_bytes(), 31);
literal_expression! { (ptr) }
}

/// Converts a storage nonce into a pointer based on the keccak256 hash
pub fn nonce_with_offset_to_ptr(nonce: usize, offset: usize) -> yul::Expression {
let ptr = get_full_signature(nonce.to_string().as_bytes());
let ptr = literal_expression! { (ptr) };
let ptr = nonce_to_ptr(nonce);
let offset = literal_expression! { (offset) };
expression! { (add([ptr], [offset])) }
}
Expand Down Expand Up @@ -566,7 +569,7 @@ mod tests {

let result = map(&harness.context, &harness.src);

assert_eq!(result, "sloadn(dualkeccak256(0, 3), 32)");
assert_eq!(result, "bytes_sloadn(map_value_ptr(0, 3), 32)");
}

#[test]
Expand Down Expand Up @@ -620,7 +623,7 @@ mod tests {

assert_eq!(
result,
"scopym(dualkeccak256(0, mloadn(add($bar_array, mul($index, 20)), 20)), 160)"
"scopym(div(map_value_ptr(0, mloadn(add($bar_array, mul($index, 32)), 32)), 32), 256)"
);
}

Expand Down
42 changes: 21 additions & 21 deletions compiler/src/yul/operations/data.rs
Expand Up @@ -7,38 +7,44 @@ use fe_analyzer::namespace::types::{
};
use yultsur::*;

/// Loads a value from storage.
///
/// The returned expression evaluates to a 256 bit value.
/// Loads a value of the given type from storage.
pub fn sload<T: FeSized>(typ: T, sptr: yul::Expression) -> yul::Expression {
let size = literal_expression! { (typ.size()) };
expression! { sloadn([sptr], [size]) }
expression! { bytes_sloadn([sptr], [size]) }
}

/// Stores a 256 bit value in storage.
/// Stores a value of the given type in storage.
pub fn sstore<T: FeSized>(typ: T, sptr: yul::Expression, value: yul::Expression) -> yul::Statement {
g-r-a-n-t marked this conversation as resolved.
Show resolved Hide resolved
let size = literal_expression! { (typ.size()) };
statement! { sstoren([sptr], [value], [size]) }
statement! { bytes_sstoren([sptr], [size], [value]) }
}

/// Loads a value of the given type from memory.
pub fn mload<T: FeSized>(typ: T, mptr: yul::Expression) -> yul::Expression {
let size = literal_expression! { (typ.size()) };
expression! { mloadn([mptr], [size]) }
}

/// Stores a 256 bit value in memory.
/// Stores a value of the given type in memory.
pub fn mstore<T: FeSized>(typ: T, mptr: yul::Expression, value: yul::Expression) -> yul::Statement {
let size = literal_expression! { (typ.size()) };
statement! { mstoren([mptr], [value], [size]) }
statement! { mstoren([mptr], [size], [value]) }
}

/// Copies a segment of memory into storage.
pub fn mcopys<T: FeSized>(typ: T, sptr: yul::Expression, mptr: yul::Expression) -> yul::Statement {
let size = literal_expression! { (typ.size()) };
statement! { mcopys([mptr], [sptr], [size]) }
let word_ptr = expression! { div([sptr], 32) };
statement! { mcopys([mptr], [word_ptr], [size]) }
}

/// Copies a segment of storage into memory.
///
/// The returned expression evaluates to a memory pointer.
/// Returns the address of the data in memory.
pub fn scopym<T: FeSized>(typ: T, sptr: yul::Expression) -> yul::Expression {
let size = literal_expression! { (typ.size()) };
expression! { scopym([sptr], [size]) }
let word_ptr = expression! { div([sptr], 32) };
expression! { scopym([word_ptr], [size]) }
}

/// Copies a segment of storage to another segment of storage.
Expand All @@ -48,7 +54,9 @@ pub fn scopys<T: FeSized>(
origin_ptr: yul::Expression,
) -> yul::Statement {
let size = literal_expression! { (typ.size()) };
statement! { scopys([origin_ptr], [dest_ptr], [size]) }
let origin_word = expression! { div([origin_ptr], 32) };
let dest_word = expression! { div([dest_ptr], 32) };
statement! { scopys([origin_word], [dest_word], [size]) }
}

/// Copies a segment of memory to another segment of memory.
Expand All @@ -57,14 +65,6 @@ pub fn mcopym<T: FeSized>(typ: T, ptr: yul::Expression) -> yul::Expression {
expression! { mcopym([ptr], [size]) }
}

/// Loads a value in memory.
///
/// The returned expression evaluates to a 256 bit value.
pub fn mload<T: FeSized>(typ: T, mptr: yul::Expression) -> yul::Expression {
let size = literal_expression! { (typ.size()) };
expression! { mloadn([mptr], [size]) }
}

/// Logs an event.
pub fn emit_event(event: Event, vals: Vec<yul::Expression>) -> yul::Statement {
let mut topics = vec![literal_expression! { (event.topic) }];
Expand Down Expand Up @@ -108,7 +108,7 @@ pub fn sum(vals: Vec<yul::Expression>) -> yul::Expression {
/// Hashes the storage nonce of a map with a key to determine the value's
/// location in storage.
pub fn keyed_map(map: yul::Expression, key: yul::Expression) -> yul::Expression {
expression! { dualkeccak256([map], [key]) }
expression! { map_value_ptr([map], [key]) }
}

/// Finds the location of an array element base on the element size, element
Expand Down