Skip to content

Commit

Permalink
endianness fix
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed Jan 15, 2025
1 parent 5c39cbb commit 83123e1
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 26 deletions.
4 changes: 2 additions & 2 deletions yarn-project/foundation/src/abi/decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ class AbiDecoder {
}
case 'struct': {
if (isU128Struct(abiType)) {
const lo = this.decodeNext({ kind: 'field' }) as bigint;
const hi = this.decodeNext({ kind: 'field' }) as bigint;
return U128.fromU64sLE(lo, hi).toInteger();
const lo = this.decodeNext({ kind: 'field' }) as bigint;
return U128.fromU64sBE(hi, lo).toInteger();
}

const struct: { [key: string]: AbiDecoded } = {};
Expand Down
7 changes: 4 additions & 3 deletions yarn-project/foundation/src/abi/encoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,12 @@ class ArgumentEncoder {
break;
}
if (isU128Struct(abiType)) {
// U128 struct has low and high limbs - so we first convert the value to the 2 limbs and then we encode them
// --> this results in the limbs being added to the final flat array as [..., lo, hi, ...].
// U128 struct has high and low limbs - so we first convert the value to the 2 limbs and then we encode them
// --> this results in the limbs being added to the final flat array as [..., hi, lo, ...] (we stick to big
// endian!).
const value = new U128(arg);
this.encodeArgument({ kind: 'field' }, value.lo, `${name}.lo`);
this.encodeArgument({ kind: 'field' }, value.hi, `${name}.hi`);
this.encodeArgument({ kind: 'field' }, value.lo, `${name}.lo`);
break;
}
if (isWrappedFieldStruct(abiType)) {
Expand Down
34 changes: 17 additions & 17 deletions yarn-project/foundation/src/abi/u128.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ describe('U128', () => {
});
});

describe('fromU64sLE', () => {
describe('fromU64sBE', () => {
it('correctly combines valid limbs', () => {
const lo = 0xdeadbeefn;
const hi = 0xcafebaben;
const combined = U128.fromU64sLE(lo, hi);
const lo = 0xdeadbeefn;
const combined = U128.fromU64sBE(hi, lo);

expect(combined.lo).toBe(lo);
expect(combined.hi).toBe(hi);
Expand All @@ -42,41 +42,41 @@ describe('U128', () => {

it('accepts maximum valid limb values', () => {
const maxLimb = 2n ** 64n - 1n;
const value = U128.fromU64sLE(maxLimb, maxLimb);
const value = U128.fromU64sBE(maxLimb, maxLimb);

expect(value.lo).toBe(maxLimb);
expect(value.hi).toBe(maxLimb);
expect(value.lo).toBe(maxLimb);
expect(value.toInteger()).toBe(2n ** 128n - 1n);
});

it('throws for invalid lower limb', () => {
const invalid = 2n ** 64n;
expect(() => U128.fromU64sLE(invalid, 0n)).toThrow(`Lower limb ${invalid} is not within valid range`);
expect(() => U128.fromU64sBE(0n, invalid)).toThrow(`Lower limb ${invalid} is not within valid range`);

expect(() => U128.fromU64sLE(-1n, 0n)).toThrow('Lower limb -1 is not within valid range');
expect(() => U128.fromU64sBE(0n, -1n)).toThrow('Lower limb -1 is not within valid range');
});

it('throws for invalid higher limb', () => {
const invalid = 2n ** 64n;
expect(() => U128.fromU64sLE(0n, invalid)).toThrow(`Higher limb ${invalid} is not within valid range`);
expect(() => U128.fromU64sBE(invalid, 0n)).toThrow(`Higher limb ${invalid} is not within valid range`);

expect(() => U128.fromU64sLE(0n, -1n)).toThrow('Higher limb -1 is not within valid range');
expect(() => U128.fromU64sBE(-1n, 0n)).toThrow('Higher limb -1 is not within valid range');
});
});

describe('getters', () => {
it('correctly extracts lo and hi components', () => {
it('correctly extracts hi and lo components', () => {
const testCases = [
{ lo: 0xdeadbeefn, hi: 0xcafebaben },
{ lo: 0n, hi: 1n },
{ lo: 1n, hi: 0n },
{ lo: 2n ** 64n - 1n, hi: 2n ** 64n - 1n },
{ hi: 0xcafebaben, lo: 0xdeadbeefn },
{ hi: 1n, lo: 0n },
{ hi: 0n, lo: 1n },
{ hi: 2n ** 64n - 1n, lo: 2n ** 64n - 1n },
];

for (const { lo, hi } of testCases) {
const value = U128.fromU64sLE(lo, hi);
expect(value.lo).toBe(lo);
for (const { hi, lo } of testCases) {
const value = U128.fromU64sBE(hi, lo);
expect(value.hi).toBe(hi);
expect(value.lo).toBe(lo);
}
});
});
Expand Down
8 changes: 4 additions & 4 deletions yarn-project/foundation/src/abi/u128.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ export class U128 {
this.value = value;
}

static fromU64sLE(lo: bigint, hi: bigint): U128 {
static fromU64sBE(hi: bigint, lo: bigint): U128 {
// Validate limbs are within valid ranges
if (lo < 0n || lo >= 2n ** 64n) {
throw new Error(`Lower limb ${lo} is not within valid range (0 to 2^64-1)`);
}
if (hi < 0n || hi >= 2n ** 64n) {
throw new Error(`Higher limb ${hi} is not within valid range (0 to 2^64-1)`);
}
if (lo < 0n || lo >= 2n ** 64n) {
throw new Error(`Lower limb ${lo} is not within valid range (0 to 2^64-1)`);
}

// Combine limbs into full value and create new instance
const value = (hi << 64n) | lo;
Expand Down

0 comments on commit 83123e1

Please sign in to comment.