From 0d65c9da4ad6d925779b9b6e8ff99bea4c25eedf Mon Sep 17 00:00:00 2001 From: Greg Hysen Date: Mon, 19 Nov 2018 16:52:45 -0800 Subject: Optimizer Tests --- packages/utils/test/abi_encoder_test.ts | 272 +++++++++++++++++++++++--------- packages/utils/test/abi_samples.ts | 88 ----------- 2 files changed, 200 insertions(+), 160 deletions(-) (limited to 'packages') diff --git a/packages/utils/test/abi_encoder_test.ts b/packages/utils/test/abi_encoder_test.ts index 9925abcc3..c5be35d5e 100644 --- a/packages/utils/test/abi_encoder_test.ts +++ b/packages/utils/test/abi_encoder_test.ts @@ -4,6 +4,7 @@ import 'mocha'; import { chaiSetup } from './utils/chai_setup'; import { BigNumber, AbiEncoder } from '../src/'; import * as AbiSamples from './abi_samples'; +import * as OptimizedAbis from './optimizer_abis'; import { DecodingRules } from '../src/abi_encoder'; import ethUtil = require('ethereumjs-util'); @@ -12,19 +13,17 @@ const expect = chai.expect; describe.only('ABI Encoder', () => { describe('Optimizer', () => { - it('Should reuse duplicate strings in string array', async () => { - // Description: - // There are two unique values in the array `strings`. - // There should exist only one copy of each string in the optimized calldata. - // In unoptimized calldata, two copies of each string will be created. + it('Duplicate Dynamic Arrays with Static Elements', async () => { // Generate calldata - const method = new AbiEncoder.Method(AbiSamples.stringAbi); - const strings = ['Test String', 'Test String 2', 'Test String', 'Test String 2']; - const args = [strings]; - // Validate calldata + const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithStaticElements); + const array1 = [new BigNumber(100), new BigNumber(150)]; + const array2 = array1; + const args = [array1, array2]; + // Validata calldata const optimizedCalldata = method.encode(args, { optimize: true }); + console.log(optimizedCalldata); const expectedOptimizedCalldata = - '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000'; + '0x7221063300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096'; expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); // Validate decoding const decodedArgs = method.decode(optimizedCalldata); @@ -32,21 +31,68 @@ describe.only('ABI Encoder', () => { const argsJson = JSON.stringify(args); expect(decodedArgsJson).to.be.equal(argsJson); }); - it('Should point array elements to a duplicate value from another parameter', async () => { - // Description: - // There are two unique values in the array `strings`. - // The value "Test String" appears three times in this array. - // There should exist only one copy of this string in the optimized calldata. - // In unoptimized calldata, "Test String" would be written three times. + it('Duplicate Dynamic Arrays with Dynamic Elements', async () => { + // Generate calldata + const method = new AbiEncoder.Method(OptimizedAbis.duplicateDynamicArraysWithDynamicElements); + const array1 = ["Hello", "World"]; + const array2 = array1; + const args = [array1, array2]; + // Validata calldata + const optimizedCalldata = method.encode(args, { optimize: true }); + const expectedOptimizedCalldata = + '0xbb4f12e300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000'; + expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); + // Validate decoding + const decodedArgs = method.decode(optimizedCalldata); + const decodedArgsJson = JSON.stringify(decodedArgs); + const argsJson = JSON.stringify(args); + expect(decodedArgsJson).to.be.equal(argsJson); + }); + it('Duplicate Static Arrays with Static Elements (should not optimize)', async () => { // Generate calldata - const method = new AbiEncoder.Method(AbiSamples.optimizerAbi2); - const strings = ['Test String', 'Test String', 'Test String', 'Test String 2']; - const string = 'Test String'; - const args = [strings, string]; + const method = new AbiEncoder.Method(OptimizedAbis.duplicateStaticArraysWithStaticElements); + const array1 = [new BigNumber(100), new BigNumber(150)]; + const array2 = array1; + const args = [array1, array2]; + // Validata calldata + const optimizedCalldata = method.encode(args, { optimize: true }); + const expectedOptimizedCalldata = + '0x7f8130430000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096'; + expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); + const unoptimizedCalldata = method.encode(args); + expect(optimizedCalldata).to.be.equal(unoptimizedCalldata); + // Validate decoding + const decodedArgs = method.decode(optimizedCalldata); + const decodedArgsJson = JSON.stringify(decodedArgs); + const argsJson = JSON.stringify(args); + expect(decodedArgsJson).to.be.equal(argsJson); + }); + it('Duplicate Static Arrays with Dynamic Elements', async () => { + // Generate calldata + const method = new AbiEncoder.Method(OptimizedAbis.duplicateStaticArraysWithDynamicElements); + const array1 = ["Hello", "World"]; + const array2 = array1; + const args = [array1, array2]; + // Validata calldata + const optimizedCalldata = method.encode(args, { optimize: true }); + const expectedOptimizedCalldata = + '0x9fe31f8e0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000'; + expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); + // Validate decoding + const decodedArgs = method.decode(optimizedCalldata); + const decodedArgsJson = JSON.stringify(decodedArgs); + const argsJson = JSON.stringify(args); + expect(decodedArgsJson).to.be.equal(argsJson); + }); + it('Duplicate Array Elements (should optimize)', async () => { + // Generate calldata + const method = new AbiEncoder.Method(OptimizedAbis.duplicateArrayElements); + const strings = ['Hello', 'World', 'Hello', 'World']; + const args = [strings]; // Validate calldata const optimizedCalldata = method.encode(args, { optimize: true }); const expectedOptimizedCalldata = - '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000d5465737420537472696e67203200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b5465737420537472696e67000000000000000000000000000000000000000000'; + '0x13e751a900000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000'; expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); // Validate decoding const decodedArgs = method.decode(optimizedCalldata); @@ -54,24 +100,15 @@ describe.only('ABI Encoder', () => { const argsJson = JSON.stringify(args); expect(decodedArgsJson).to.be.equal(argsJson); }); - it('Dynamic Array of uints should point to Dynamic Array of Tuple(Uint)s', async () => { - // Description: - // There are two dynamic arrays, one of uint's and one of tuples. - // Each tuple is simply a wrapper for a uint - tuple := {key: uintValue} - // While the elements of these arrays have different types, they - // have the same representation in calldata. - // That is, a `uint` and a `tuple{uint}` both consume exactly one word of calldata. - // In the optimized calldata, only the elements of one array should be included. - // Both arrays will then point to the same set of elements. + it('Duplicate Tuple Fields', async () => { // Generate calldata - const method = new AbiEncoder.Method(AbiSamples.optimizerAbi3); - const uint8Array = [new BigNumber(100), new BigNumber(150), new BigNumber(200), new BigNumber(225)]; - const uintTupleArray = [[uint8Array[0]], [uint8Array[1]], [uint8Array[2]], [uint8Array[3]]]; - const args = [uint8Array, uintTupleArray]; + const method = new AbiEncoder.Method(OptimizedAbis.duplicateTupleFields); + const tuple = ['Hello', 'Hello']; + const args = [tuple]; // Validata calldata const optimizedCalldata = method.encode(args, { optimize: true }); const expectedOptimizedCalldata = - '0x5b5c78fd0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000e1'; + '0x16780a5e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000'; expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); // Validate decoding const decodedArgs = method.decode(optimizedCalldata); @@ -79,20 +116,18 @@ describe.only('ABI Encoder', () => { const argsJson = JSON.stringify(args); expect(decodedArgsJson).to.be.equal(argsJson); }); - it('Duplicate Dynamic Arrays', async () => { + it('Duplicate Strings', async () => { // Description: // Two dynamic arrays with the same values. // In the optimized calldata, only one set of elements should be included. // Both arrays should point to this set. // Generate calldata - const method = new AbiEncoder.Method(AbiSamples.optimizerAbi5); - const array1 = [new BigNumber(100), new BigNumber(150)]; - const array2 = [array1[0], array1[1]]; - const args = [array1, array2]; + const method = new AbiEncoder.Method(OptimizedAbis.duplicateStrings); + const args = ['Hello', 'Hello']; // Validata calldata const optimizedCalldata = method.encode(args, { optimize: true }); const expectedOptimizedCalldata = - '0x7bc4226e00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096'; + '0x07370bfa00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000'; expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); // Validate decoding const decodedArgs = method.decode(optimizedCalldata); @@ -100,22 +135,19 @@ describe.only('ABI Encoder', () => { const argsJson = JSON.stringify(args); expect(decodedArgsJson).to.be.equal(argsJson); }); - - /* - it.only('Duplicate Static Arrays', async () => { + it('Duplicate Bytes', async () => { // Description: // Two dynamic arrays with the same values. // In the optimized calldata, only one set of elements should be included. // Both arrays should point to this set. // Generate calldata - const method = new AbiEncoder.Method(AbiSamples.optimizerAbi5); - const array1 = [new BigNumber(100), new BigNumber(150)]; - const array2 = [array1[0], array1[1]]; - const args = [array1, array2]; + const method = new AbiEncoder.Method(OptimizedAbis.duplicateBytes); + const value = '0x01020304050607080910111213141516171819202122232425262728293031323334353637383940'; + const args = [value, value]; // Validata calldata const optimizedCalldata = method.encode(args, { optimize: true }); const expectedOptimizedCalldata = - '0x7bc4226e00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096'; + '0x6045e42900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002801020304050607080910111213141516171819202122232425262728293031323334353637383940000000000000000000000000000000000000000000000000'; expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); // Validate decoding const decodedArgs = method.decode(optimizedCalldata); @@ -123,49 +155,145 @@ describe.only('ABI Encoder', () => { const argsJson = JSON.stringify(args); expect(decodedArgsJson).to.be.equal(argsJson); }); - - it.only('Duplicate Tuples', async () => { + it('Duplicate Tuples', async () => { + // Generate calldata + const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuples); + const tuple1 = ['Hello, World!', new BigNumber(424234)]; + const tuple2 = tuple1; + const args = [tuple1, tuple2]; + // Validata calldata + const optimizedCalldata = method.encode(args, { optimize: true }); + const expectedOptimizedCalldata = + '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000006792a000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000'; + expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); + // Validate decoding + const decodedArgs = method.decode(optimizedCalldata); + const decodedArgsJson = JSON.stringify(decodedArgs); + const argsJson = JSON.stringify(args); + expect(decodedArgsJson).to.be.equal(argsJson); + }); + it('Duplicate Fields Across Two Tuples', async () => { // Description: - // Two dynamic arrays with the same values. - // In the optimized calldata, only one set of elements should be included. - // Both arrays should point to this set. // Generate calldata - const method = new AbiEncoder.Method(AbiSamples.optimizerAbi5); - const array1 = [new BigNumber(100), new BigNumber(150)]; - const array2 = [array1[0], array1[1]]; - const args = [array1, array2]; + const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuples); + const tuple1 = ['Hello, World!', new BigNumber(1)]; + const tuple2 = [tuple1[0], new BigNumber(2)]; + const args = [tuple1, tuple2]; // Validata calldata const optimizedCalldata = method.encode(args, { optimize: true }); const expectedOptimizedCalldata = - '0x7bc4226e00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000096'; + '0x564f826d000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c642100000000000000000000000000000000000000'; expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); // Validate decoding const decodedArgs = method.decode(optimizedCalldata); const decodedArgsJson = JSON.stringify(decodedArgs); const argsJson = JSON.stringify(args); expect(decodedArgsJson).to.be.equal(argsJson); - });*/ - - it('Static Array of static types should not be optimized', async () => { + }); + it('Duplicate Arrays, Nested in Separate Tuples', async () => { + // Generate calldata + const method = new AbiEncoder.Method(OptimizedAbis.duplicateArraysNestedInTuples); + const array = [new BigNumber(100), new BigNumber(150), new BigNumber(200)]; + const tuple1 = [array]; + const tuple2 = [array, 'extra argument to prevent exactly matching the tuples']; + const args = [tuple1, tuple2]; + // Validata calldata + const optimizedCalldata = method.encode(args, { optimize: true }); + const expectedOptimizedCalldata = + '0x18970a9e000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c80000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000'; + expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); + // Validate decoding + const decodedArgs = method.decode(optimizedCalldata); + const decodedArgsJson = JSON.stringify(decodedArgs); + const argsJson = JSON.stringify(args); + expect(decodedArgsJson).to.be.equal(argsJson); + }); + it('Duplicate Tuples, Nested in Separate Tuples', async () => { // Generate calldata - const method = new AbiEncoder.Method(AbiSamples.optimizerAbi4); - const uint8Array = [new BigNumber(100), new BigNumber(150), new BigNumber(200), new BigNumber(225)]; - const uintTupleArray = [[uint8Array[0]], [uint8Array[1]], [uint8Array[2]], [uint8Array[3]]]; - const args = [uint8Array, uintTupleArray]; + const method = new AbiEncoder.Method(OptimizedAbis.duplicateTuplesNestedInTuples); + const nestedTuple = ['Hello, World!']; + const tuple1 = [nestedTuple]; + const tuple2 = [nestedTuple, 'extra argument to prevent exactly matching the tuples']; + const args = [tuple1, tuple2]; + // Validata calldata + const optimizedCalldata = method.encode(args, { optimize: true }); + const expectedOptimizedCalldata = + '0x0b4d2e6a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c6421000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035657874726120617267756d656e7420746f2070726576656e742065786163746c79206d61746368696e6720746865207475706c65730000000000000000000000'; + expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); + // Validate decoding + const decodedArgs = method.decode(optimizedCalldata); + const decodedArgsJson = JSON.stringify(decodedArgs); + const argsJson = JSON.stringify(args); + expect(decodedArgsJson).to.be.equal(argsJson); + }); + it('Duplicate Two-Dimensional Arrays', async () => { + // Generate calldata + const method = new AbiEncoder.Method(OptimizedAbis.duplicateTwoDimensionalArrays); + const twoDimArray1 = [['Hello', 'World'], ['Foo', 'Bar', 'Zaa']]; + const twoDimArray2 = twoDimArray1; + const args = [twoDimArray1, twoDimArray2]; + // Validata calldata + const optimizedCalldata = method.encode(args, { optimize: false }); + const expectedOptimizedCalldata = + '0x0d28c4f9000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003466f6f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003426172000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035a61610000000000000000000000000000000000000000000000000000000000'; + expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); + // Validate decoding + const decodedArgs = method.decode(optimizedCalldata); + const decodedArgsJson = JSON.stringify(decodedArgs); + const argsJson = JSON.stringify(args); + expect(decodedArgsJson).to.be.equal(argsJson); + }); + it('Duplicate Array, Nested within Separate Two-Dimensional Arrays', async () => { + // Generate calldata + const method = new AbiEncoder.Method(OptimizedAbis.duplicateTwoDimensionalArrays); + const twoDimArray1 = [['Hello', 'World'], ['Foo']]; + const twoDimArray2 = [['Hello', 'World'], ['Bar']]; + const args = [twoDimArray1, twoDimArray2]; + // Validata calldata + const optimizedCalldata = method.encode(args, { optimize: true }); + const expectedOptimizedCalldata = + '0x0d28c4f900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003466f6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000548656c6c6f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005576f726c640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000034261720000000000000000000000000000000000000000000000000000000000'; + expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); + // Validate decoding + const decodedArgs = method.decode(optimizedCalldata); + const decodedArgsJson = JSON.stringify(decodedArgs); + const argsJson = JSON.stringify(args); + expect(decodedArgsJson).to.be.equal(argsJson); + }); + it('Array Elements Duplicated as Tuple Fields', async () => { + // Generate calldata + const method = new AbiEncoder.Method(OptimizedAbis.arrayElementsDuplicatedAsTupleFields); + const array = [new BigNumber(100), new BigNumber(150), new BigNumber(200), new BigNumber(225)]; + const tuple = [[array[0]], [array[1]], [array[2]], [array[3]]]; + const args = [array, tuple]; + // Validata calldata + const optimizedCalldata = method.encode(args, { optimize: true }); + const expectedOptimizedCalldata = + '0x5b5c78fd0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000009600000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000e1'; + expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); + // Validate decoding + const decodedArgs = method.decode(optimizedCalldata); + const decodedArgsJson = JSON.stringify(decodedArgs); + const argsJson = JSON.stringify(args); + expect(decodedArgsJson).to.be.equal(argsJson); + }); + it('Array Elements Duplicated as Separate Parameter', async () => { + // Generate calldata + const method = new AbiEncoder.Method(OptimizedAbis.arrayElementsDuplicatedAsSeparateParameter); + const array = ['Hello', 'Hello', 'Hello', 'World']; + const string = 'Hello'; + const args = [array, string]; // Validate calldata const optimizedCalldata = method.encode(args, { optimize: true }); - const unoptimizedCalldata = method.encode(args); - expect(optimizedCalldata).to.be.equal(unoptimizedCalldata); + const expectedOptimizedCalldata = + '0xe0e0d34900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000005576f726c64000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000548656c6c6f000000000000000000000000000000000000000000000000000000'; + expect(optimizedCalldata).to.be.equal(expectedOptimizedCalldata); // Validate decoding const decodedArgs = method.decode(optimizedCalldata); const decodedArgsJson = JSON.stringify(decodedArgs); const argsJson = JSON.stringify(args); expect(decodedArgsJson).to.be.equal(argsJson); }); - - // Todo: Unfixed array points to fixed array - // Todo: Unfixed to unfixed array - // Todo: Duplicate tuples }); describe('Method ABIs', () => { diff --git a/packages/utils/test/abi_samples.ts b/packages/utils/test/abi_samples.ts index 806ad1700..0c3354044 100644 --- a/packages/utils/test/abi_samples.ts +++ b/packages/utils/test/abi_samples.ts @@ -68,94 +68,6 @@ export const GAbi = { type: 'function', } as MethodAbi; -export const optimizerAbi2 = { - constant: false, - inputs: [ - { - name: 'stringArray', - type: 'string[]', - }, - { - name: 'string', - type: 'string', - }, - ], - name: 'simpleFunction', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', -} as MethodAbi; - -export const optimizerAbi3 = { - constant: false, - inputs: [ - { - name: 'uint8Array', - type: 'uint8[]', - }, - { - components: [ - { - name: 'uint', - type: 'uint', - }, - ], - name: 'uintTuple', - type: 'tuple[]', - }, - ], - name: 'simpleFunction', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', -} as MethodAbi; - -export const optimizerAbi4 = { - constant: false, - inputs: [ - { - name: 'uint8Array', - type: 'uint8[4]', - }, - { - components: [ - { - name: 'uint', - type: 'uint', - }, - ], - name: 'uintTuple', - type: 'tuple[]', - }, - ], - name: 'simpleFunction', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', -} as MethodAbi; - -export const optimizerAbi5 = { - constant: false, - inputs: [ - { - name: 'array1', - type: 'uint8[]', - }, - { - name: 'array2', - type: 'uint8[]', - }, - ], - name: 'simpleFunction', - outputs: [], - payable: false, - stateMutability: 'nonpayable', - type: 'function', -} as MethodAbi; - export const typesWithDefaultWidthsAbi = { constant: false, inputs: [ -- cgit v1.2.3