referrerpolicy=no-referrer-when-downgrade

pallet_revive/vm/evm/instructions/
utility.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use revm::primitives::{Address, B256, U256};
19
20/// Pushes an arbitrary length slice of bytes onto the stack, padding the last word with zeros
21/// if necessary.
22///
23/// # Panics
24///
25/// Panics if slice is longer than 32 bytes.
26#[inline]
27pub fn cast_slice_to_u256(slice: &[u8], dest: &mut U256) {
28	if slice.is_empty() {
29		return;
30	}
31	assert!(slice.len() <= 32, "slice too long");
32
33	let n_words = slice.len().div_ceil(32);
34
35	// SAFETY: Length checked above.
36	unsafe {
37		//let dst = self.data.as_mut_ptr().add(self.data.len()).cast::<u64>();
38		//self.data.set_len(new_len);
39		let dst = dest.as_limbs_mut().as_mut_ptr();
40
41		let mut i = 0;
42
43		// Write full words
44		let words = slice.chunks_exact(32);
45		let partial_last_word = words.remainder();
46		for word in words {
47			// Note: We unroll `U256::from_be_bytes` here to write directly into the buffer,
48			// instead of creating a 32 byte array on the stack and then copying it over.
49			for l in word.rchunks_exact(8) {
50				dst.add(i).write(u64::from_be_bytes(l.try_into().unwrap()));
51				i += 1;
52			}
53		}
54
55		if partial_last_word.is_empty() {
56			return;
57		}
58
59		// Write limbs of partial last word
60		let limbs = partial_last_word.rchunks_exact(8);
61		let partial_last_limb = limbs.remainder();
62		for l in limbs {
63			dst.add(i).write(u64::from_be_bytes(l.try_into().unwrap()));
64			i += 1;
65		}
66
67		// Write partial last limb by padding with zeros
68		if !partial_last_limb.is_empty() {
69			let mut tmp = [0u8; 8];
70			tmp[8 - partial_last_limb.len()..].copy_from_slice(partial_last_limb);
71			dst.add(i).write(u64::from_be_bytes(tmp));
72			i += 1;
73		}
74
75		debug_assert_eq!(i.div_ceil(4), n_words, "wrote too much");
76
77		// Zero out upper bytes of last word
78		let m = i % 4; // 32 / 8
79		if m != 0 {
80			dst.add(i).write_bytes(0, 4 - m);
81		}
82	}
83}
84
85/// Trait for converting types into U256 values.
86pub trait IntoU256 {
87	/// Converts the implementing type into a U256 value.
88	fn into_u256(self) -> U256;
89}
90
91impl IntoU256 for Address {
92	fn into_u256(self) -> U256 {
93		self.into_word().into_u256()
94	}
95}
96
97impl IntoU256 for B256 {
98	fn into_u256(self) -> U256 {
99		U256::from_be_bytes(self.0)
100	}
101}
102
103/// Trait for converting types into Address values.
104pub trait IntoAddress {
105	/// Converts the implementing type into an Address value.
106	fn into_address(self) -> Address;
107}
108
109impl IntoAddress for U256 {
110	fn into_address(self) -> Address {
111		Address::from_word(B256::from(self.to_be_bytes()))
112	}
113}
114
115#[cfg(test)]
116mod tests {
117	use revm::primitives::address;
118
119	use super::*;
120
121	#[test]
122	fn test_into_u256() {
123		let addr = address!("0x0000000000000000000000000000000000000001");
124		let u256 = addr.into_u256();
125		assert_eq!(u256, U256::from(0x01));
126		assert_eq!(u256.into_address(), addr);
127	}
128}