aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmir Bandeali <abandeali1@gmail.com>2018-05-10 07:27:50 +0800
committerAmir Bandeali <abandeali1@gmail.com>2018-05-31 08:11:30 +0800
commita5a7217c8f24fe98275fd9927ca8c5e5f140c6f3 (patch)
treef58846c928d05047265b471638eab11d627bdc99
parentc0cf55b40bb4a13cfd94a506bf125f6eb57c6767 (diff)
downloaddexon-sol-tools-a5a7217c8f24fe98275fd9927ca8c5e5f140c6f3.tar
dexon-sol-tools-a5a7217c8f24fe98275fd9927ca8c5e5f140c6f3.tar.gz
dexon-sol-tools-a5a7217c8f24fe98275fd9927ca8c5e5f140c6f3.tar.bz2
dexon-sol-tools-a5a7217c8f24fe98275fd9927ca8c5e5f140c6f3.tar.lz
dexon-sol-tools-a5a7217c8f24fe98275fd9927ca8c5e5f140c6f3.tar.xz
dexon-sol-tools-a5a7217c8f24fe98275fd9927ca8c5e5f140c6f3.tar.zst
dexon-sol-tools-a5a7217c8f24fe98275fd9927ca8c5e5f140c6f3.zip
Add deepCopyBytes method to LibBytes
-rw-r--r--packages/contracts/src/contracts/current/test/TestLibBytes/TestLibBytes.sol17
-rw-r--r--packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol41
-rw-r--r--packages/contracts/test/libraries/lib_bytes.ts34
3 files changed, 92 insertions, 0 deletions
diff --git a/packages/contracts/src/contracts/current/test/TestLibBytes/TestLibBytes.sol b/packages/contracts/src/contracts/current/test/TestLibBytes/TestLibBytes.sol
index 5a6801262..b3ed1f620 100644
--- a/packages/contracts/src/contracts/current/test/TestLibBytes/TestLibBytes.sol
+++ b/packages/contracts/src/contracts/current/test/TestLibBytes/TestLibBytes.sol
@@ -25,6 +25,23 @@ contract TestLibBytes is
LibBytes
{
+ /// @dev Performs a deep copy of a section of a byte array.
+ /// @param b Byte array that will be sliced.
+ /// @param startIndex Index of first byte to copy.
+ /// @param endIndex Index of last byte to copy + 1.
+ /// @return A deep copy of b from startIndex to endIndex.
+ function publicDeepCopyBytes(
+ bytes memory b,
+ uint256 startIndex,
+ uint256 endIndex)
+ public
+ pure
+ returns (bytes memory copy)
+ {
+ copy = deepCopyBytes(b, startIndex, endIndex);
+ return copy;
+ }
+
/// @dev Tests equality of two byte arrays.
/// @param lhs First byte array to compare.
/// @param rhs Second byte array to compare.
diff --git a/packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol b/packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol
index 975565773..527f7a7a9 100644
--- a/packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol
+++ b/packages/contracts/src/contracts/current/utils/LibBytes/LibBytes.sol
@@ -21,9 +21,50 @@ pragma solidity ^0.4.24;
contract LibBytes {
// Revert reasons
+ string constant GT_ZERO_LENGTH_REQUIRED = "Length must be greater than 0.";
string constant GTE_4_LENGTH_REQUIRED = "Length must be greater than or equal to 4.";
string constant GTE_20_LENGTH_REQUIRED = "Length must be greater than or equal to 20.";
string constant GTE_32_LENGTH_REQUIRED = "Length must be greater than or equal to 32.";
+ string constant INDEX_OUT_OF_BOUNDS = "Specified array index is out of bounds.";
+
+ /// @dev Performs a deep copy of a section of a byte array.
+ /// @param b Byte array that will be copied.
+ /// @param index Index of first byte to copy.
+ /// @param len Number of bytes to copy starting from index.
+ /// @return A deep copy `len` bytes of b starting from index.
+ function deepCopyBytes(
+ bytes memory b,
+ uint256 index,
+ uint256 len)
+ internal
+ pure
+ returns (bytes memory)
+ {
+ require(
+ len > 0,
+ GT_ZERO_LENGTH_REQUIRED
+ );
+ require(
+ b.length >= index + len,
+ INDEX_OUT_OF_BOUNDS
+ );
+
+ bytes memory copy = new bytes(len);
+
+ // Arrays are prefixed by a 256 bit length parameter
+ index += 32;
+
+ assembly {
+ // Start storing onto copy after length field
+ let storeStartIndex := add(copy, 32)
+ // Start loading from b at index
+ let startLoadIndex := add(b, index)
+ for {let i := 0} lt(i, len) {i := add(i, 32)} {
+ mstore(add(storeStartIndex, i), mload(add(startLoadIndex, i)))
+ }
+ }
+ return copy;
+ }
/// @dev Tests equality of two byte arrays.
/// @param lhs First byte array to compare.
diff --git a/packages/contracts/test/libraries/lib_bytes.ts b/packages/contracts/test/libraries/lib_bytes.ts
index 968bac300..1fd30a3e0 100644
--- a/packages/contracts/test/libraries/lib_bytes.ts
+++ b/packages/contracts/test/libraries/lib_bytes.ts
@@ -60,6 +60,40 @@ describe('LibBytes', () => {
await blockchainLifecycle.revertAsync();
});
+ describe.only('deepCopyBytes', () => {
+ const byteArrayLongerThan32BytesLen = (byteArrayLongerThan32Bytes.length - 2) / 2;
+ it('should throw if length of copy is 0', async () => {
+ const index = new BigNumber(0);
+ const len = new BigNumber(0);
+ return expect(
+ libBytes.publicDeepCopyBytes.callAsync(byteArrayLongerThan32Bytes, index, len),
+ ).to.be.rejectedWith(constants.REVERT);
+ });
+
+ it('should throw if start index + length to copy is greater than length of byte array', async () => {
+ const index = new BigNumber(0);
+ const len = new BigNumber(byteArrayLongerThan32BytesLen + 1);
+ return expect(
+ libBytes.publicDeepCopyBytes.callAsync(byteArrayLongerThan32Bytes, index, len),
+ ).to.be.rejectedWith(constants.REVERT);
+ });
+
+ it('should copy the entire byte array if index = 0 and len = b.length', async () => {
+ const index = new BigNumber(0);
+ const len = new BigNumber(byteArrayLongerThan32BytesLen);
+ const copy = await libBytes.publicDeepCopyBytes.callAsync(byteArrayLongerThan32Bytes, index, len);
+ expect(copy).to.equal(byteArrayLongerThan32Bytes);
+ });
+
+ it('should copy part of the byte array if area to copy is less than b.length', async () => {
+ const index = new BigNumber(10);
+ const len = new BigNumber(4);
+ const copy = await libBytes.publicDeepCopyBytes.callAsync(byteArrayLongerThan32Bytes, index, len);
+ const expectedCopy = `0x${byteArrayLongerThan32Bytes.slice(22, 30)}`;
+ expect(copy).to.equal(expectedCopy);
+ });
+ });
+
describe('areBytesEqual', () => {
it('should return true if byte arrays are equal (both arrays < 32 bytes)', async () => {
const areBytesEqual = await libBytes.publicAreBytesEqual.callAsync(