From c870b25018cc9a7940a999aedc6462447e2d1816 Mon Sep 17 00:00:00 2001 From: Cameron Manavian Date: Tue, 18 Apr 2023 21:31:06 -0700 Subject: [PATCH 1/8] add coverage --- packages/abi-coder/src/utilities.test.ts | 481 +++++++++++++++++++++++ 1 file changed, 481 insertions(+) create mode 100644 packages/abi-coder/src/utilities.test.ts diff --git a/packages/abi-coder/src/utilities.test.ts b/packages/abi-coder/src/utilities.test.ts new file mode 100644 index 00000000000..e77ba76ca7b --- /dev/null +++ b/packages/abi-coder/src/utilities.test.ts @@ -0,0 +1,481 @@ +import AbiCoder from './abi-coder'; +import { ParamType } from './fragments/param-type'; +import type { JsonAbiFragmentType } from './json-abi'; +import { filterEmptyParams, hasOptionTypes, getVectorAdjustments } from './utilities'; + +describe('Abi Coder Utilities', () => { + it('can filterEmptyParams', () => { + const INPUT: ParamType[] = [ + new ParamType({ + type: '()', + }), + new ParamType({ + type: 'enum Option', + }), + new ParamType({ + type: '()', + }), + ]; + const EXPECTED = [ + new ParamType({ + type: 'enum Option', + }), + ]; + + const RESULT = filterEmptyParams(INPUT); + expect(RESULT).toStrictEqual(EXPECTED); + }); + + it('can determine if types array hasOptionTypes [true]', () => { + const INPUT: ParamType[] = [ + new ParamType({ + type: 'enum Option', + }), + ]; + + const RESULT = hasOptionTypes(INPUT); + expect(RESULT).toStrictEqual(true); + }); + + it('can determine if types array hasOptionTypes [false]', () => { + const INPUT: ParamType[] = [ + new ParamType({ + type: 'struct Vec', + }), + ]; + + const RESULT = hasOptionTypes(INPUT); + expect(RESULT).toStrictEqual(false); + }); + + it('can getVectorAdjustments [no Vectors, offset = 0]', () => { + const abiCoder = new AbiCoder(); + const NON_EMPTY_TYPES: ReadonlyArray = [ + { + type: 'b256', + name: 'arg0', + }, + { + type: 'b256', + name: 'arg1', + }, + ]; + const CODERS = NON_EMPTY_TYPES.map((type) => abiCoder.getCoder(type)); + const VALUES = [43]; + const EXPECTED: Uint8Array[] = []; + + const RESULT = getVectorAdjustments(CODERS, VALUES, 0); + expect(RESULT).toStrictEqual(EXPECTED); + }); + + it('can getVectorAdjustments [no Vectors, offset = 8]', () => { + const abiCoder = new AbiCoder(); + const NON_EMPTY_TYPES: ReadonlyArray = [ + { + type: 'b256', + name: 'arg0', + }, + { + type: 'b256', + name: 'arg1', + }, + ]; + const CODERS = NON_EMPTY_TYPES.map((type) => abiCoder.getCoder(type)); + const VALUES = [43]; + const EXPECTED: Uint8Array[] = []; + + const RESULT = getVectorAdjustments(CODERS, VALUES, 8); + expect(RESULT).toStrictEqual(EXPECTED); + }); + + it('can getVectorAdjustments [inputs=[Vector], offset = 0]', () => { + const abiCoder = new AbiCoder(); + const NON_EMPTY_TYPES: ReadonlyArray = [ + { + name: 'vector', + type: 'struct Vec', + components: [ + { + name: 'buf', + type: 'struct RawVec', + components: [ + { + name: 'ptr', + type: 'raw untyped ptr', + }, + { + name: 'cap', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u8', + }, + ], + }, + { + name: 'len', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u8', + }, + ], + }, + ]; + const CODERS = NON_EMPTY_TYPES.map((type) => abiCoder.getCoder(type)); + const VALUES = [[1, 2, 34]]; + const EXPECTED: Uint8Array[] = [ + new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 34]), + ]; + + const RESULT = getVectorAdjustments(CODERS, VALUES, 0); + expect(RESULT).toStrictEqual(EXPECTED); + }); + + it('can getVectorAdjustments [inputs=[Vector], offset = 36]', () => { + const abiCoder = new AbiCoder(); + const NON_EMPTY_TYPES: ReadonlyArray = [ + { + name: 'vector', + type: 'struct Vec', + components: [ + { + name: 'buf', + type: 'struct RawVec', + components: [ + { + name: 'ptr', + type: 'raw untyped ptr', + }, + { + name: 'cap', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u8', + }, + ], + }, + { + name: 'len', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u8', + }, + ], + }, + ]; + const CODERS = NON_EMPTY_TYPES.map((type) => abiCoder.getCoder(type)); + const VALUES = [[1, 2, 34]]; + const EXPECTED: Uint8Array[] = [ + new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 34]), + ]; + + const RESULT = getVectorAdjustments(CODERS, VALUES, 36); + expect(RESULT).toStrictEqual(EXPECTED); + }); + + it('can getVectorAdjustments [inputs=[Vector, Vector], offset = 0]', () => { + const abiCoder = new AbiCoder(); + const NON_EMPTY_TYPES: ReadonlyArray = [ + { + name: 'vector', + type: 'struct Vec', + components: [ + { + name: 'buf', + type: 'struct RawVec', + components: [ + { + name: 'ptr', + type: 'raw untyped ptr', + }, + { + name: 'cap', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u8', + }, + ], + }, + { + name: 'len', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u8', + }, + ], + }, + { + name: 'vector', + type: 'struct Vec', + components: [ + { + name: 'buf', + type: 'struct RawVec', + components: [ + { + name: 'ptr', + type: 'raw untyped ptr', + }, + { + name: 'cap', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u8', + }, + ], + }, + { + name: 'len', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u8', + }, + ], + }, + ]; + const CODERS = NON_EMPTY_TYPES.map((type) => abiCoder.getCoder(type)); + const VALUES = [ + [1, 2, 34], + [71, 72, 99], + ]; + const EXPECTED: Uint8Array[] = [ + new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 34]), + new Uint8Array([0, 0, 0, 0, 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 99]), + ]; + + const RESULT = getVectorAdjustments(CODERS, VALUES, 0); + expect(RESULT).toStrictEqual(EXPECTED); + }); + + it('can getVectorAdjustments [inputs=[Vector,Vector], offset = 0]', () => { + const abiCoder = new AbiCoder(); + const NON_EMPTY_TYPES: ReadonlyArray = [ + { + name: 'vector', + type: 'struct Vec', + components: [ + { + name: 'buf', + type: 'struct RawVec', + components: [ + { + name: 'ptr', + type: 'raw untyped ptr', + }, + { + name: 'cap', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u8', + }, + ], + }, + { + name: 'len', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u8', + }, + ], + }, + { + name: 'vector', + type: 'struct Vec', + components: [ + { + name: 'buf', + type: 'struct RawVec', + components: [ + { + name: 'ptr', + type: 'raw untyped ptr', + }, + { + name: 'cap', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + { + name: 'len', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + ]; + const CODERS = NON_EMPTY_TYPES.map((type) => abiCoder.getCoder(type)); + const VALUES = [ + [7, 2, 34], + [867, 5309, 1337], + ]; + const EXPECTED: Uint8Array[] = [ + new Uint8Array([0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 34]), + new Uint8Array([0, 0, 0, 0, 0, 0, 3, 99, 0, 0, 0, 0, 0, 0, 20, 189, 0, 0, 0, 0, 0, 0, 5, 57]), + ]; + + const RESULT = getVectorAdjustments(CODERS, VALUES, 36); + expect(RESULT).toStrictEqual(EXPECTED); + }); + + it('can getVectorAdjustments [inputs=[Vector,b256], offset = 8]', () => { + const abiCoder = new AbiCoder(); + const NON_EMPTY_TYPES: ReadonlyArray = [ + { + name: 'vector', + type: 'struct Vec', + components: [ + { + name: 'buf', + type: 'struct RawVec', + components: [ + { + name: 'ptr', + type: 'raw untyped ptr', + }, + { + name: 'cap', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u8', + }, + ], + }, + { + name: 'len', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u8', + }, + ], + }, + { + type: 'b256', + name: 'arg1', + }, + ]; + const CODERS = NON_EMPTY_TYPES.map((type) => abiCoder.getCoder(type)); + const VALUES = [[1, 3, 3, 7], 43]; + const EXPECTED: Uint8Array[] = [ + new Uint8Array([ + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, + 7, + ]), + ]; + + const RESULT = getVectorAdjustments(CODERS, VALUES, 8); + expect(RESULT).toStrictEqual(EXPECTED); + }); + + it('can getVectorAdjustments [inputs=[b256,Vector], offset = 14440]', () => { + const abiCoder = new AbiCoder(); + const NON_EMPTY_TYPES: ReadonlyArray = [ + { + type: 'u32', + name: 'arg1', + }, + { + name: 'vector', + type: 'struct Vec', + components: [ + { + name: 'buf', + type: 'struct RawVec', + components: [ + { + name: 'ptr', + type: 'raw untyped ptr', + }, + { + name: 'cap', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + { + name: 'len', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + ]; + const CODERS = NON_EMPTY_TYPES.map((type) => abiCoder.getCoder(type)); + const VALUES = [33, [450, 202, 340]]; + const EXPECTED: Uint8Array[] = [ + new Uint8Array([0, 0, 0, 0, 0, 0, 1, 194, 0, 0, 0, 0, 0, 0, 0, 202, 0, 0, 0, 0, 0, 0, 1, 84]), + ]; + + const RESULT = getVectorAdjustments(CODERS, VALUES, 14440); + expect(RESULT).toStrictEqual(EXPECTED); + }); +}); From b14a393aca80b472809ce1e7162dd20f2cd47b64 Mon Sep 17 00:00:00 2001 From: Cameron Manavian Date: Tue, 18 Apr 2023 21:31:59 -0700 Subject: [PATCH 2/8] add edge cases --- .../fuel-gauge/src/coverage-contract.test.ts | 26 +++++++++++++++++++ .../coverage-contract/src/main.sw | 20 ++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/packages/fuel-gauge/src/coverage-contract.test.ts b/packages/fuel-gauge/src/coverage-contract.test.ts index 1b12066bced..14a9dc7d3a8 100644 --- a/packages/fuel-gauge/src/coverage-contract.test.ts +++ b/packages/fuel-gauge/src/coverage-contract.test.ts @@ -473,4 +473,30 @@ describe('Coverage Contract', () => { expect(value.map((v: BN) => v.toNumber())).toStrictEqual([1, 2, 3]); }); + + it('should try vec_as_only_param', async () => { + const { value } = await contractInstance.functions + .vec_as_only_param([100, 450, 202, 340]) + .call(); + + expect(value.map((v: BN) => v.toHex())).toStrictEqual([ + bn(4).toHex(), + bn(100).toHex(), + bn(450).toHex(), + bn(202).toHex(), + ]); + }); + + it('should try u32_and_vec_params', async () => { + const { value } = await contractInstance.functions + .u32_and_vec_params(33, [450, 202, 340]) + .call(); + + expect(value.map((v: BN) => v.toHex())).toStrictEqual([ + bn(3).toHex(), + bn(450).toHex(), + bn(202).toHex(), + bn(340).toHex(), + ]); + }); }); diff --git a/packages/fuel-gauge/test-projects/coverage-contract/src/main.sw b/packages/fuel-gauge/test-projects/coverage-contract/src/main.sw index ae78cc38f82..759d22266c3 100644 --- a/packages/fuel-gauge/test-projects/coverage-contract/src/main.sw +++ b/packages/fuel-gauge/test-projects/coverage-contract/src/main.sw @@ -96,6 +96,8 @@ abi CoverageContract { fn get_u64_vector() -> raw_slice; fn echo_u8_vector(input: Vec) -> raw_slice; fn echo_u64_vector(input: Vec) -> raw_slice; + fn vec_as_only_param(input: Vec) -> (u64, Option, Option, Option); + fn u32_and_vec_params(foo: u32, input: Vec) -> (u64, Option, Option, Option); } impl CoverageContract for Contract { @@ -344,4 +346,22 @@ impl CoverageContract for Contract { fn echo_u64_vector(input: Vec) -> raw_slice { input.as_raw_slice() } + + fn vec_as_only_param(input: Vec) -> (u64, Option, Option, Option) { + ( + input.len(), + input.get(0), + input.get(1), + input.get(2), + ) + } + + fn u32_and_vec_params(foo: u32, input: Vec) -> (u64, Option, Option, Option) { + ( + input.len(), + input.get(0), + input.get(1), + input.get(2), + ) + } } From 3d21f9418c42e3a570ecae969048c7281a47309a Mon Sep 17 00:00:00 2001 From: Cameron Manavian Date: Tue, 18 Apr 2023 22:33:04 -0700 Subject: [PATCH 3/8] capture bug --- packages/abi-coder/src/abi-coder.test.ts | 120 +++++++++++++++++++++++ packages/abi-coder/src/utilities.test.ts | 36 ++++++- 2 files changed, 151 insertions(+), 5 deletions(-) diff --git a/packages/abi-coder/src/abi-coder.test.ts b/packages/abi-coder/src/abi-coder.test.ts index 271a3bd2397..f9a0416e5bf 100644 --- a/packages/abi-coder/src/abi-coder.test.ts +++ b/packages/abi-coder/src/abi-coder.test.ts @@ -368,4 +368,124 @@ describe('AbiCoder', () => { expect(hexlify(encoded)).toBe(expected); }); + + it('encodes inputs with [mixed params + vector second param + with offset]', () => { + const types = [ + { + name: 'vector', + type: 'struct Vec', + components: [ + { + name: 'buf', + type: 'struct RawVec', + components: [ + { + name: 'ptr', + type: 'raw untyped ptr', + }, + { + name: 'cap', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + { + name: 'len', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + ]; + + const vector = [450, 202, 1340]; + const encoded = abiCoder.encode(types, [vector], 14440); + + const pointer = [0, 0, 0, 0, 0, 0, 56, 128]; + const capacity = [0, 0, 0, 0, 0, 0, 0, vector.length]; + const length = [0, 0, 0, 0, 0, 0, 0, vector.length]; + const data1 = [0, 0, 0, 0, 0, 0, Math.floor(vector[0] / 256), vector[0] % 256]; + const data2 = [0, 0, 0, 0, 0, 0, 0, vector[1]]; + const data3 = [0, 0, 0, 0, 0, 0, Math.floor(vector[2] / 256), vector[2] % 256]; + const inputAndVecData = concat([pointer, capacity, length, data1, data2, data3]); + + const expected = hexlify(inputAndVecData); + + expect(encoded).toStrictEqual(inputAndVecData); + expect(hexlify(encoded)).toBe(expected); + }); + + it('encodes inputs with [mixed params + vector second param + with offset]', () => { + const types = [ + { + type: 'u32', + name: 'arg1', + }, + { + name: 'vector', + type: 'struct Vec', + components: [ + { + name: 'buf', + type: 'struct RawVec', + components: [ + { + name: 'ptr', + type: 'raw untyped ptr', + }, + { + name: 'cap', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + { + name: 'len', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + ]; + + const u32 = 72; + const vector = [450, 202, 1340]; + const encoded = abiCoder.encode(types, [u32, vector], 14440); + + const encodedU32 = [0, 0, 0, 0, 0, 0, 0, u32]; + const pointer = [0, 0, 0, 0, 0, 0, 56, 128]; + const capacity = [0, 0, 0, 0, 0, 0, 0, vector.length]; + const length = [0, 0, 0, 0, 0, 0, 0, vector.length]; + const data1 = [0, 0, 0, 0, 0, 0, Math.floor(vector[0] / 256), vector[0] % 256]; + const data2 = [0, 0, 0, 0, 0, 0, 0, vector[1]]; + const data3 = [0, 0, 0, 0, 0, 0, Math.floor(vector[2] / 256), vector[2] % 256]; + const inputAndVecData = concat([encodedU32, pointer, capacity, length, data1, data2, data3]); + + const expected = hexlify(inputAndVecData); + + expect(encoded).toStrictEqual(inputAndVecData); + expect(hexlify(encoded)).toBe(expected); + }); }); diff --git a/packages/abi-coder/src/utilities.test.ts b/packages/abi-coder/src/utilities.test.ts index e77ba76ca7b..004443c38dc 100644 --- a/packages/abi-coder/src/utilities.test.ts +++ b/packages/abi-coder/src/utilities.test.ts @@ -1,4 +1,6 @@ import AbiCoder from './abi-coder'; +import VecCoder from './coders/vec'; +import { WORD_SIZE } from './constants'; import { ParamType } from './fragments/param-type'; import type { JsonAbiFragmentType } from './json-abi'; import { filterEmptyParams, hasOptionTypes, getVectorAdjustments } from './utilities'; @@ -136,9 +138,10 @@ describe('Abi Coder Utilities', () => { const RESULT = getVectorAdjustments(CODERS, VALUES, 0); expect(RESULT).toStrictEqual(EXPECTED); + expect(CODERS[0].offset).toStrictEqual(VecCoder.getBaseOffset()); }); - it('can getVectorAdjustments [inputs=[Vector], offset = 36]', () => { + it('can getVectorAdjustments [inputs=[Vector], offset = 32]', () => { const abiCoder = new AbiCoder(); const NON_EMPTY_TYPES: ReadonlyArray = [ { @@ -180,12 +183,14 @@ describe('Abi Coder Utilities', () => { ]; const CODERS = NON_EMPTY_TYPES.map((type) => abiCoder.getCoder(type)); const VALUES = [[1, 2, 34]]; + const OFFSET = 32; const EXPECTED: Uint8Array[] = [ new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 34]), ]; - const RESULT = getVectorAdjustments(CODERS, VALUES, 36); + const RESULT = getVectorAdjustments(CODERS, VALUES, OFFSET); expect(RESULT).toStrictEqual(EXPECTED); + expect(CODERS[0].offset).toStrictEqual(VecCoder.getBaseOffset() + OFFSET); }); it('can getVectorAdjustments [inputs=[Vector, Vector], offset = 0]', () => { @@ -276,9 +281,15 @@ describe('Abi Coder Utilities', () => { const RESULT = getVectorAdjustments(CODERS, VALUES, 0); expect(RESULT).toStrictEqual(EXPECTED); + // one base vec offset per each vector input + expect(CODERS[0].offset).toStrictEqual(VecCoder.getBaseOffset() + VecCoder.getBaseOffset()); + // one base vec offset per each vector input + the first vector's data + expect(CODERS[1].offset).toStrictEqual( + VecCoder.getBaseOffset() + VecCoder.getBaseOffset() + VALUES[0].length * WORD_SIZE + ); }); - it('can getVectorAdjustments [inputs=[Vector,Vector], offset = 0]', () => { + it('can getVectorAdjustments [inputs=[Vector,Vector], offset = 32]', () => { const abiCoder = new AbiCoder(); const NON_EMPTY_TYPES: ReadonlyArray = [ { @@ -359,13 +370,22 @@ describe('Abi Coder Utilities', () => { [7, 2, 34], [867, 5309, 1337], ]; + const OFFSET = 32; const EXPECTED: Uint8Array[] = [ new Uint8Array([0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 34]), new Uint8Array([0, 0, 0, 0, 0, 0, 3, 99, 0, 0, 0, 0, 0, 0, 20, 189, 0, 0, 0, 0, 0, 0, 5, 57]), ]; - const RESULT = getVectorAdjustments(CODERS, VALUES, 36); + const RESULT = getVectorAdjustments(CODERS, VALUES, OFFSET); expect(RESULT).toStrictEqual(EXPECTED); + // one base vec offset per each vector input + plus custom OFFSET + expect(CODERS[0].offset).toStrictEqual( + VecCoder.getBaseOffset() + VecCoder.getBaseOffset() + OFFSET + ); + // one base vec offset per each vector input + the first vector's data + plus custom OFFSET + expect(CODERS[1].offset).toStrictEqual( + VecCoder.getBaseOffset() + VecCoder.getBaseOffset() + VALUES[0].length * WORD_SIZE + OFFSET + ); }); it('can getVectorAdjustments [inputs=[Vector,b256], offset = 8]', () => { @@ -414,6 +434,7 @@ describe('Abi Coder Utilities', () => { ]; const CODERS = NON_EMPTY_TYPES.map((type) => abiCoder.getCoder(type)); const VALUES = [[1, 3, 3, 7], 43]; + const OFFSET = 8; const EXPECTED: Uint8Array[] = [ new Uint8Array([ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, @@ -421,8 +442,10 @@ describe('Abi Coder Utilities', () => { ]), ]; - const RESULT = getVectorAdjustments(CODERS, VALUES, 8); + const RESULT = getVectorAdjustments(CODERS, VALUES, OFFSET); expect(RESULT).toStrictEqual(EXPECTED); + // one base vec offset + plus b256 data + plus custom OFFSET + expect(CODERS[0].offset).toStrictEqual(VecCoder.getBaseOffset() + 4 * WORD_SIZE + OFFSET); }); it('can getVectorAdjustments [inputs=[b256,Vector], offset = 14440]', () => { @@ -471,11 +494,14 @@ describe('Abi Coder Utilities', () => { ]; const CODERS = NON_EMPTY_TYPES.map((type) => abiCoder.getCoder(type)); const VALUES = [33, [450, 202, 340]]; + const OFFSET = 14440; const EXPECTED: Uint8Array[] = [ new Uint8Array([0, 0, 0, 0, 0, 0, 1, 194, 0, 0, 0, 0, 0, 0, 0, 202, 0, 0, 0, 0, 0, 0, 1, 84]), ]; const RESULT = getVectorAdjustments(CODERS, VALUES, 14440); expect(RESULT).toStrictEqual(EXPECTED); + // one base vec offset + plus custom OFFSET + expect(CODERS[0].offset).toStrictEqual(VecCoder.getBaseOffset() + OFFSET); }); }); From 4e024f024fda12e6a72ba4f5735111c502b558b2 Mon Sep 17 00:00:00 2001 From: Cameron Manavian Date: Tue, 18 Apr 2023 22:58:33 -0700 Subject: [PATCH 4/8] works --- packages/abi-coder/src/utilities.test.ts | 4 ++-- packages/abi-coder/src/utilities.ts | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/abi-coder/src/utilities.test.ts b/packages/abi-coder/src/utilities.test.ts index 004443c38dc..baec1189419 100644 --- a/packages/abi-coder/src/utilities.test.ts +++ b/packages/abi-coder/src/utilities.test.ts @@ -501,7 +501,7 @@ describe('Abi Coder Utilities', () => { const RESULT = getVectorAdjustments(CODERS, VALUES, 14440); expect(RESULT).toStrictEqual(EXPECTED); - // one base vec offset + plus custom OFFSET - expect(CODERS[0].offset).toStrictEqual(VecCoder.getBaseOffset() + OFFSET); + // one base vec offset + plus u32 data + plus custom OFFSET + expect(CODERS[1].offset).toStrictEqual(VecCoder.getBaseOffset() + WORD_SIZE + OFFSET); }); }); diff --git a/packages/abi-coder/src/utilities.ts b/packages/abi-coder/src/utilities.ts index 8896b6721e8..c18b42a5013 100644 --- a/packages/abi-coder/src/utilities.ts +++ b/packages/abi-coder/src/utilities.ts @@ -21,10 +21,14 @@ export function getVectorAdjustments( offset = 0 ) { const vectorData: Uint8Array[] = []; + let firstVectorIndex = -1; const byteMap: ByteInfo[] = coders.map((encoder, i) => { if (!(encoder instanceof VecCoder)) { return { byteLength: encoder.encodedLength }; } + if (firstVectorIndex === -1) { + firstVectorIndex = i; + } // eslint-disable-next-line @typescript-eslint/no-explicit-any const data = encoder.getEncodedVectorData(values[i] as any); @@ -39,14 +43,22 @@ export function getVectorAdjustments( } return byteMap.reduce((sum, byteInfo, byteIndex) => { + // non-vector data if ('byteLength' in byteInfo) { return sum + byteInfo.byteLength; } + // first vector is also zero index if (byteIndex === 0 && byteIndex === paramIndex) { return baseVectorOffset; } + // first vector in input list + if (firstVectorIndex === paramIndex) { + return sum + baseVectorOffset; + } + + // account for other vectors at earlier in input list if (byteIndex < paramIndex) { return sum + byteInfo.vecByteLength + baseVectorOffset; } From d77ceaa751a07cc4f37cedce8dd5a3011385b1d1 Mon Sep 17 00:00:00 2001 From: Cameron Manavian Date: Tue, 18 Apr 2023 23:13:30 -0700 Subject: [PATCH 5/8] fix edge --- packages/abi-coder/src/utilities.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/abi-coder/src/utilities.ts b/packages/abi-coder/src/utilities.ts index c18b42a5013..e1980c949b3 100644 --- a/packages/abi-coder/src/utilities.ts +++ b/packages/abi-coder/src/utilities.ts @@ -53,8 +53,8 @@ export function getVectorAdjustments( return baseVectorOffset; } - // first vector in input list - if (firstVectorIndex === paramIndex) { + // first vector in input list but not zero index + if (byteIndex === firstVectorIndex && firstVectorIndex === paramIndex) { return sum + baseVectorOffset; } From 2dc211b19b389ba2a83e543d91e76bd00585e31a Mon Sep 17 00:00:00 2001 From: Cameron Manavian Date: Tue, 18 Apr 2023 23:28:22 -0700 Subject: [PATCH 6/8] solve issues --- packages/abi-coder/src/abi-coder.test.ts | 2 +- packages/abi-coder/src/utilities.test.ts | 141 ++++++++++++++++++++++- packages/abi-coder/src/utilities.ts | 15 ++- 3 files changed, 153 insertions(+), 5 deletions(-) diff --git a/packages/abi-coder/src/abi-coder.test.ts b/packages/abi-coder/src/abi-coder.test.ts index f9a0416e5bf..9aabed4aaeb 100644 --- a/packages/abi-coder/src/abi-coder.test.ts +++ b/packages/abi-coder/src/abi-coder.test.ts @@ -475,7 +475,7 @@ describe('AbiCoder', () => { const encoded = abiCoder.encode(types, [u32, vector], 14440); const encodedU32 = [0, 0, 0, 0, 0, 0, 0, u32]; - const pointer = [0, 0, 0, 0, 0, 0, 56, 128]; + const pointer = [0, 0, 0, 0, 0, 0, 56, 136]; const capacity = [0, 0, 0, 0, 0, 0, 0, vector.length]; const length = [0, 0, 0, 0, 0, 0, 0, vector.length]; const data1 = [0, 0, 0, 0, 0, 0, Math.floor(vector[0] / 256), vector[0] % 256]; diff --git a/packages/abi-coder/src/utilities.test.ts b/packages/abi-coder/src/utilities.test.ts index baec1189419..101767db051 100644 --- a/packages/abi-coder/src/utilities.test.ts +++ b/packages/abi-coder/src/utilities.test.ts @@ -499,9 +499,148 @@ describe('Abi Coder Utilities', () => { new Uint8Array([0, 0, 0, 0, 0, 0, 1, 194, 0, 0, 0, 0, 0, 0, 0, 202, 0, 0, 0, 0, 0, 0, 1, 84]), ]; - const RESULT = getVectorAdjustments(CODERS, VALUES, 14440); + const RESULT = getVectorAdjustments(CODERS, VALUES, OFFSET); expect(RESULT).toStrictEqual(EXPECTED); // one base vec offset + plus u32 data + plus custom OFFSET expect(CODERS[1].offset).toStrictEqual(VecCoder.getBaseOffset() + WORD_SIZE + OFFSET); }); + + it('can getVectorAdjustments [inputs=[b256,Vector,Vector,Vector], offset = 24]', () => { + const abiCoder = new AbiCoder(); + const NON_EMPTY_TYPES: ReadonlyArray = [ + { + type: 'u32', + name: 'arg1', + }, + { + name: 'vector', + type: 'struct Vec', + components: [ + { + name: 'buf', + type: 'struct RawVec', + components: [ + { + name: 'ptr', + type: 'raw untyped ptr', + }, + { + name: 'cap', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + { + name: 'len', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + { + name: 'vector', + type: 'struct Vec', + components: [ + { + name: 'buf', + type: 'struct RawVec', + components: [ + { + name: 'ptr', + type: 'raw untyped ptr', + }, + { + name: 'cap', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + { + name: 'len', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + { + name: 'vector', + type: 'struct Vec', + components: [ + { + name: 'buf', + type: 'struct RawVec', + components: [ + { + name: 'ptr', + type: 'raw untyped ptr', + }, + { + name: 'cap', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + { + name: 'len', + type: 'u64', + }, + ], + typeArguments: [ + { + name: '', + type: 'u64', + }, + ], + }, + ]; + const CODERS = NON_EMPTY_TYPES.map((type) => abiCoder.getCoder(type)); + const VALUES = [33, [450, 202, 340], [12, 13, 14], [11, 9]]; + const OFFSET = 24; + const EXPECTED: Uint8Array[] = [ + new Uint8Array([0, 0, 0, 0, 0, 0, 1, 194, 0, 0, 0, 0, 0, 0, 0, 202, 0, 0, 0, 0, 0, 0, 1, 84]), + new Uint8Array([0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 14]), + new Uint8Array([0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 9]), + ]; + + const OFFSET_PLUS_DATA_PLUS_3_OFFSETS = VecCoder.getBaseOffset() * 3 + WORD_SIZE + OFFSET; + + const RESULT = getVectorAdjustments(CODERS, VALUES, OFFSET); + expect(RESULT).toStrictEqual(EXPECTED); + // three base vec offset + plus u32 data + plus custom OFFSET + expect(CODERS[1].offset).toStrictEqual(OFFSET_PLUS_DATA_PLUS_3_OFFSETS); + // three base vec offset + plus u32 data + the first vector's data + plus custom OFFSET + expect(CODERS[2].offset).toStrictEqual(OFFSET_PLUS_DATA_PLUS_3_OFFSETS + 3 * WORD_SIZE); + // three base vec offset + plus u32 data + the first vector's data + the second vector's data + plus custom OFFSET + expect(CODERS[3].offset).toStrictEqual( + OFFSET_PLUS_DATA_PLUS_3_OFFSETS + 3 * WORD_SIZE + 3 * WORD_SIZE + ); + }); }); diff --git a/packages/abi-coder/src/utilities.ts b/packages/abi-coder/src/utilities.ts index e1980c949b3..b5ca0f3ab3b 100644 --- a/packages/abi-coder/src/utilities.ts +++ b/packages/abi-coder/src/utilities.ts @@ -42,6 +42,7 @@ export function getVectorAdjustments( return 0; } + let hasUsedBaseOffset = false; return byteMap.reduce((sum, byteInfo, byteIndex) => { // non-vector data if ('byteLength' in byteInfo) { @@ -49,20 +50,28 @@ export function getVectorAdjustments( } // first vector is also zero index - if (byteIndex === 0 && byteIndex === paramIndex) { + if (byteIndex === 0 && byteIndex === paramIndex && !hasUsedBaseOffset) { + hasUsedBaseOffset = true; return baseVectorOffset; } // first vector in input list but not zero index - if (byteIndex === firstVectorIndex && firstVectorIndex === paramIndex) { + if (byteIndex === firstVectorIndex && firstVectorIndex === paramIndex && !hasUsedBaseOffset) { + hasUsedBaseOffset = true; return sum + baseVectorOffset; } // account for other vectors at earlier in input list - if (byteIndex < paramIndex) { + if (byteIndex < paramIndex && !hasUsedBaseOffset) { + hasUsedBaseOffset = true; return sum + byteInfo.vecByteLength + baseVectorOffset; } + /// account for other vectors at earlier in input list without offset + if (byteIndex < paramIndex) { + return sum + byteInfo.vecByteLength; + } + return sum; }, 0); }); From 18ff8c929baf74a689ca453fbc6845280e95011f Mon Sep 17 00:00:00 2001 From: Cameron Manavian Date: Tue, 18 Apr 2023 23:34:07 -0700 Subject: [PATCH 7/8] simplify --- packages/abi-coder/src/utilities.ts | 31 ++++++----------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/packages/abi-coder/src/utilities.ts b/packages/abi-coder/src/utilities.ts index b5ca0f3ab3b..5ed294e38b8 100644 --- a/packages/abi-coder/src/utilities.ts +++ b/packages/abi-coder/src/utilities.ts @@ -21,14 +21,10 @@ export function getVectorAdjustments( offset = 0 ) { const vectorData: Uint8Array[] = []; - let firstVectorIndex = -1; const byteMap: ByteInfo[] = coders.map((encoder, i) => { if (!(encoder instanceof VecCoder)) { return { byteLength: encoder.encodedLength }; } - if (firstVectorIndex === -1) { - firstVectorIndex = i; - } // eslint-disable-next-line @typescript-eslint/no-explicit-any const data = encoder.getEncodedVectorData(values[i] as any); @@ -36,44 +32,29 @@ export function getVectorAdjustments( return { vecByteLength: data.byteLength }; }); + if (!vectorData.length) { + return vectorData; + } + const baseVectorOffset = vectorData.length * VecCoder.getBaseOffset() + offset; const offsetMap = coders.map((encoder, paramIndex) => { if (!(encoder instanceof VecCoder)) { return 0; } - let hasUsedBaseOffset = false; return byteMap.reduce((sum, byteInfo, byteIndex) => { // non-vector data if ('byteLength' in byteInfo) { return sum + byteInfo.byteLength; } - // first vector is also zero index - if (byteIndex === 0 && byteIndex === paramIndex && !hasUsedBaseOffset) { - hasUsedBaseOffset = true; - return baseVectorOffset; - } - - // first vector in input list but not zero index - if (byteIndex === firstVectorIndex && firstVectorIndex === paramIndex && !hasUsedBaseOffset) { - hasUsedBaseOffset = true; - return sum + baseVectorOffset; - } - - // account for other vectors at earlier in input list - if (byteIndex < paramIndex && !hasUsedBaseOffset) { - hasUsedBaseOffset = true; - return sum + byteInfo.vecByteLength + baseVectorOffset; - } - - /// account for other vectors at earlier in input list without offset + // account for preceding vector data earlier in input list if (byteIndex < paramIndex) { return sum + byteInfo.vecByteLength; } return sum; - }, 0); + }, baseVectorOffset); }); coders.forEach((code, i) => code.setOffset(offsetMap[i])); From 442e6d4f8a99f42004cc52ac87140102ef7b50ec Mon Sep 17 00:00:00 2001 From: Cameron Manavian Date: Tue, 18 Apr 2023 23:34:55 -0700 Subject: [PATCH 8/8] add CS --- .changeset/gorgeous-plants-tap.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/gorgeous-plants-tap.md diff --git a/.changeset/gorgeous-plants-tap.md b/.changeset/gorgeous-plants-tap.md new file mode 100644 index 00000000000..e2d22a56b3d --- /dev/null +++ b/.changeset/gorgeous-plants-tap.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/abi-coder": minor +--- + +Fix vector inputs when the first item is not a vector