Skip to content

Commit 8a47c6b

Browse files
authored
Merge pull request #78 from algorandfoundation/fix/type-length
fix: arc4 encoded length of native boolean should be 1 instead of 8
2 parents 30e01e8 + 630f576 commit 8a47c6b

File tree

4 files changed

+23
-29
lines changed

4 files changed

+23
-29
lines changed

src/encoders.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { biguint, bytes, OnCompleteAction, TransactionType, uint64 } from '@algorandfoundation/algorand-typescript'
22
import { ARC4Encoded } from '@algorandfoundation/algorand-typescript/arc4'
33
import { encodingUtil } from '@algorandfoundation/puya-ts'
4-
import { InternalError } from './errors'
4+
import { CodeError, InternalError } from './errors'
55
import { BytesBackedCls, Uint64BackedCls } from './impl/base'
6-
import { arc4Encoders, encodeArc4Impl, getArc4Encoder, tryArc4EncodedLengthImpl } from './impl/encoded-types'
6+
import { arc4Encoders, encodeArc4Impl, getArc4Encoder, getMaxLengthOfStaticContentType } from './impl/encoded-types'
77
import { BigUint, Uint64, type StubBytesCompat } from './impl/primitives'
88
import { AccountCls, ApplicationCls, AssetCls } from './impl/reference'
99
import type { DeliberateAny } from './typescript-helpers'
@@ -90,7 +90,13 @@ export const toBytes = (val: unknown): bytes => {
9090
throw new InternalError(`Invalid type for bytes: ${nameOfType(val)}`)
9191
}
9292

93-
export const minLengthForType = (typeInfo: TypeInfo): number => {
94-
const minArc4StaticLength = tryArc4EncodedLengthImpl(typeInfo)
95-
return minArc4StaticLength ?? 0
93+
export const minLengthForType = (typeInfo: TypeInfo): number | undefined => {
94+
try {
95+
return getMaxLengthOfStaticContentType(typeInfo, false)
96+
} catch (e) {
97+
if (e instanceof CodeError && e.message.startsWith('unsupported type')) {
98+
return undefined
99+
}
100+
throw e
101+
}
96102
}

src/impl/encoded-types.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1103,14 +1103,14 @@ const findBoolTypes = (values: TypeInfo[], index: number, delta: number): number
11031103
return until
11041104
}
11051105

1106-
const getMaxLengthOfStaticContentType = (type: TypeInfo): number => {
1106+
export const getMaxLengthOfStaticContentType = (type: TypeInfo, asArc4Encoded: boolean = true): number => {
11071107
switch (trimGenericTypeName(type.name)) {
11081108
case 'uint64':
11091109
return UINT64_SIZE / BITS_IN_BYTE
11101110
case 'biguint':
11111111
return UINT512_SIZE / BITS_IN_BYTE
11121112
case 'boolean':
1113-
return 8
1113+
return asArc4Encoded ? 1 : 8
11141114
case 'Bool':
11151115
return 1
11161116
case 'Address':
@@ -1409,17 +1409,5 @@ export const getArc4Encoded = (value: DeliberateAny, sourceTypeInfoString?: stri
14091409

14101410
export const arc4EncodedLengthImpl = (typeInfoString: string): uint64 => {
14111411
const typeInfo = JSON.parse(typeInfoString)
1412-
return getMaxLengthOfStaticContentType(typeInfo)
1413-
}
1414-
1415-
export const tryArc4EncodedLengthImpl = (typeInfoString: string | TypeInfo): uint64 | undefined => {
1416-
const typeInfo = typeof typeInfoString === 'string' ? JSON.parse(typeInfoString) : typeInfoString
1417-
try {
1418-
return getMaxLengthOfStaticContentType(typeInfo)
1419-
} catch (e) {
1420-
if (e instanceof CodeError && e.message.startsWith('unsupported type')) {
1421-
return undefined
1422-
}
1423-
throw e
1424-
}
1412+
return getMaxLengthOfStaticContentType(typeInfo, true)
14251413
}

src/impl/state.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { lazyContext } from '../context-helpers/internal-context'
1717
import type { TypeInfo } from '../encoders'
1818
import { getEncoder, minLengthForType, toBytes } from '../encoders'
1919
import { AssertError, CodeError, InternalError } from '../errors'
20-
import { getGenericTypeInfo, tryArc4EncodedLengthImpl } from '../runtime-helpers'
20+
import { getGenericTypeInfo } from '../runtime-helpers'
2121
import { asBytes, asBytesCls, asNumber, asUint8Array, conactUint8Arrays } from '../util'
2222
import type { StubBytesCompat, StubUint64Compat } from './primitives'
2323
import { Bytes, Uint64, Uint64Cls } from './primitives'
@@ -162,7 +162,7 @@ export class BoxCls<TValue> {
162162

163163
create(options?: { size?: StubUint64Compat }): boolean {
164164
const optionSize = options?.size !== undefined ? asNumber(options.size) : undefined
165-
const valueTypeSize = tryArc4EncodedLengthImpl(this.valueType)
165+
const valueTypeSize = minLengthForType(this.valueType)
166166
if (valueTypeSize === undefined && optionSize === undefined) {
167167
throw new InternalError(`${this.valueType.name} does not have a fixed byte size. Please specify a size argument`)
168168
}
@@ -176,11 +176,7 @@ export class BoxCls<TValue> {
176176
)
177177
}
178178
}
179-
lazyContext.ledger.setBox(
180-
this.#app,
181-
this.key,
182-
new Uint8Array(Math.max(asNumber(options?.size ?? 0), this.valueType ? minLengthForType(this.valueType) : 0)),
183-
)
179+
lazyContext.ledger.setBox(this.#app, this.key, new Uint8Array(Math.max(asNumber(options?.size ?? 0), valueTypeSize ?? 0)))
184180
return true
185181
}
186182

@@ -198,7 +194,7 @@ export class BoxCls<TValue> {
198194
return materialised
199195
}
200196
set value(v: TValue) {
201-
const isStaticValueType = tryArc4EncodedLengthImpl(this.valueType) !== undefined
197+
const isStaticValueType = minLengthForType(this.valueType) !== undefined
202198
const newValueBytes = asUint8Array(toBytes(v))
203199
if (isStaticValueType && this.exists) {
204200
const originalValueBytes = lazyContext.ledger.getBox(this.#app, this.key)

tests/arc4/encode-decode-arc4.spec.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,12 +225,16 @@ describe('arc4EncodedLength', () => {
225225
expect(arc4EncodedLength<uint64>()).toEqual(8)
226226
expect(arc4EncodedLength<biguint>()).toEqual(64)
227227
expect(arc4EncodedLength<Bool>()).toEqual(1)
228-
expect(arc4EncodedLength<boolean>()).toEqual(8)
228+
expect(arc4EncodedLength<boolean>()).toEqual(1)
229229
expect(arc4EncodedLength<UintN<512>>()).toEqual(64)
230230
expect(arc4EncodedLength<[uint64, uint64, boolean]>()).toEqual(17)
231231
expect(arc4EncodedLength<[uint64, uint64, boolean, boolean]>()).toEqual(17)
232232
expect(arc4EncodedLength<Tuple<[StaticArray<Bool, 10>, Bool]>>()).toEqual(3)
233233
expect(arc4EncodedLength<StaticStruct>()).toEqual(395)
234+
expect(arc4EncodedLength<[StaticArray<Bool, 10>, boolean, boolean]>()).toEqual(3)
235+
expect(
236+
arc4EncodedLength<[[boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean], boolean, boolean]>(),
237+
).toEqual(3)
234238
})
235239
})
236240

0 commit comments

Comments
 (0)