Skip to content

Commit 627c06e

Browse files
committed
implement gloadBytes, gloadUint64, Block, and add tests for those
1 parent fff9126 commit 627c06e

File tree

6 files changed

+130
-13
lines changed

6 files changed

+130
-13
lines changed

src/impl/block.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { bytes, internal, uint64 } from '@algorandfoundation/algorand-typescript'
2+
import { lazyContext } from '../context-helpers/internal-context'
3+
import { itob } from './pure'
4+
import { asUint64 } from '../util'
5+
6+
export const Block: internal.opTypes.BlockType = {
7+
blkSeed: function (a: internal.primitives.StubUint64Compat): bytes {
8+
return itob(lazyContext.ledger.getBlockContent(a).seed)
9+
},
10+
blkTimestamp: function (a: internal.primitives.StubUint64Compat): uint64 {
11+
return asUint64(lazyContext.ledger.getBlockContent(a).timestamp)
12+
},
13+
}

src/impl/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export { GTxn } from './gtxn'
88
export * from './pure'
99
export { Txn, gaid } from './txn'
1010
export { GITxn, ITxn, ITxnCreate } from './itxn'
11-
export { Scratch } from './scratch'
11+
export { Scratch, gloadBytes, gloadUint64 } from './scratch'
12+
export { Block } from './block'

src/impl/scratch.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,44 @@
11
import { bytes, internal, uint64 } from '@algorandfoundation/algorand-typescript'
22
import { lazyContext } from '../context-helpers/internal-context'
33

4+
export const gloadUint64: internal.opTypes.GloadUint64Type = (
5+
a: internal.primitives.StubUint64Compat,
6+
b: internal.primitives.StubUint64Compat,
7+
): uint64 => {
8+
const txn = lazyContext.activeGroup.getTransaction(a)
9+
const result = txn.getScratchSlot(b)
10+
if (result instanceof internal.primitives.Uint64Cls) {
11+
return result as uint64
12+
}
13+
throw new internal.errors.InternalError('invalid scratch slot type')
14+
}
15+
16+
export const gloadBytes: internal.opTypes.GloadBytesType = (
17+
a: internal.primitives.StubUint64Compat,
18+
b: internal.primitives.StubUint64Compat,
19+
): bytes => {
20+
const txn = lazyContext.activeGroup.getTransaction(a)
21+
const result = txn.getScratchSlot(b)
22+
if (result instanceof internal.primitives.BytesCls) {
23+
return result as bytes
24+
}
25+
throw new internal.errors.InternalError('invalid scratch slot type')
26+
}
27+
428
export const Scratch: internal.opTypes.ScratchType = {
529
loadBytes: function (a: internal.primitives.StubUint64Compat): bytes {
630
const result = lazyContext.activeGroup.activeTransaction.getScratchSlot(a)
731
if (result instanceof internal.primitives.BytesCls) {
832
return result as bytes
933
}
10-
throw new internal.errors.InternalError('Invalid scratch slot type')
34+
throw new internal.errors.InternalError('invalid scratch slot type')
1135
},
1236
loadUint64: function (a: internal.primitives.StubUint64Compat): uint64 {
1337
const result = lazyContext.activeGroup.activeTransaction.getScratchSlot(a)
1438
if (result instanceof internal.primitives.Uint64Cls) {
1539
return result as uint64
1640
}
17-
throw new internal.errors.InternalError('Invalid scratch slot type')
41+
throw new internal.errors.InternalError('invalid scratch slot type')
1842
},
1943
store: function (
2044
a: internal.primitives.StubUint64Compat,

src/impl/txn.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,10 @@
11
import { Account, Application, arc4, Asset, bytes, internal, TransactionType, uint64 } from '@algorandfoundation/algorand-typescript'
22
import { lazyContext } from '../context-helpers/internal-context'
33
import { asNumber, asUint64, asUint64Cls } from '../util'
4-
// import {
5-
// getApplicationTransaction,
6-
// getAssetConfigTransaction,
7-
// getAssetFreezeTransaction,
8-
// getAssetTransferTransaction,
9-
// getKeyRegistrationTransaction,
10-
// getPaymentTransaction,
11-
// getTransaction,
12-
// } from './gtxn'
134

145
export const gaid = (a: internal.primitives.StubUint64Compat): uint64 => {
156
const group = lazyContext.activeGroup
16-
const transaction = group.transactions[asNumber(a)]
7+
const transaction = group.getTransaction(a)
178
if (transaction.type === TransactionType.ApplicationCall) {
189
return transaction.createdApp.id
1910
} else if (transaction.type === TransactionType.AssetConfig) {

src/subcontexts/ledger-context.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,19 @@ import { AssetData } from '../impl/asset'
77
import { GlobalData } from '../impl/global'
88
import { asBigInt, asMaybeUint64Cls, asUint64, asUint64Cls, iterBigInt } from '../util'
99

10+
interface BlockData {
11+
seed: bigint
12+
timestamp: bigint
13+
}
14+
1015
export class LedgerContext {
1116
appIdIter = iterBigInt(1001n, MAX_UINT64)
1217
assetIdIter = iterBigInt(1001n, MAX_UINT64)
1318
applicationDataMap = new Map<bigint, ApplicationData>()
1419
appIdContractMap = new Map<bigint, BaseContract>()
1520
accountDataMap = new AccountMap<AccountData>()
1621
assetDataMap = new Map<bigint, AssetData>()
22+
blocks = new Map<bigint, BlockData>()
1723
globalData = new GlobalData()
1824

1925
addAppIdContractMap(appId: internal.primitives.StubUint64Compat, contract: BaseContract): void {
@@ -76,4 +82,24 @@ export class LedgerContext {
7682
...data,
7783
}
7884
}
85+
86+
setBlock(
87+
index: internal.primitives.StubUint64Compat,
88+
seed: internal.primitives.StubUint64Compat,
89+
timestamp: internal.primitives.StubUint64Compat,
90+
): void {
91+
const i = asBigInt(index)
92+
const s = asBigInt(seed)
93+
const t = asBigInt(timestamp)
94+
95+
this.blocks.set(i, { seed: s, timestamp: t })
96+
}
97+
98+
getBlockContent(index: internal.primitives.StubUint64Compat): BlockData {
99+
const i = asBigInt(index)
100+
if (this.blocks.has(i)) {
101+
return this.blocks.get(i)!
102+
}
103+
throw internal.errors.internalError(`Block ${i} not set`)
104+
}
79105
}

tests/state-op-codes.spec.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
INITIAL_BALANCE_MICRO_ALGOS,
3333
} from './avm-invoker'
3434
import { asUint8Array } from './util'
35+
import { Block, gloadBytes, gloadUint64 } from '../src/impl'
3536

3637
describe('State op codes', async () => {
3738
const ctx = new TestExecutionContext()
@@ -376,4 +377,65 @@ describe('State op codes', async () => {
376377
expect(() => ctx.txn.lastGroup.getScratchSlot(256)).toThrow('invalid scratch slot')
377378
})
378379
})
380+
381+
describe('gloadBytes', async () => {
382+
it('should return the correct field value of the scratch slot', async () => {
383+
ctx.txn.createScope([ctx.any.txn.applicationCall({ scratchSpace: [Uint64(0), Bytes('hello'), Bytes('world')] })]).execute(() => {
384+
const slot1 = gloadBytes(0, 1)
385+
const slot2 = gloadBytes(0, 2)
386+
expect(slot1).toStrictEqual('hello')
387+
expect(slot2).toStrictEqual('world')
388+
})
389+
})
390+
it('should throw error if the scratch slot is not a bytes type', async () => {
391+
ctx.txn.createScope([ctx.any.txn.applicationCall({ scratchSpace: [Uint64(0), Bytes('hello'), Bytes('world')] })]).execute(() => {
392+
expect(() => gloadBytes(0, 0)).toThrow('invalid scratch slot type')
393+
})
394+
})
395+
it('should throw error if the scratch slot is out of range', async () => {
396+
ctx.txn.createScope([ctx.any.txn.applicationCall({ scratchSpace: [Uint64(0), Bytes('hello'), Bytes('world')] })]).execute(() => {
397+
expect(() => gloadBytes(0, 256)).toThrow('invalid scratch slot')
398+
})
399+
})
400+
})
401+
402+
describe('gloadUint64', async () => {
403+
it('should return the correct field value of the scratch slot', async () => {
404+
ctx.txn.createScope([ctx.any.txn.applicationCall({ scratchSpace: [Uint64(7), Uint64(42), Bytes('world')] })]).execute(() => {
405+
const slot0 = gloadUint64(0, 0)
406+
const slot1 = gloadUint64(0, 1)
407+
expect(slot0).toStrictEqual(7n)
408+
expect(slot1).toStrictEqual(42n)
409+
})
410+
})
411+
it('should throw error if the scratch slot is not a uint64 type', async () => {
412+
ctx.txn.createScope([ctx.any.txn.applicationCall({ scratchSpace: [Uint64(7), Uint64(42), Bytes('world')] })]).execute(() => {
413+
expect(() => gloadUint64(0, 2)).toThrow('invalid scratch slot type')
414+
})
415+
})
416+
it('should throw error if the scratch slot is out of range', async () => {
417+
ctx.txn.createScope([ctx.any.txn.applicationCall({ scratchSpace: [Uint64(7), Uint64(42), Bytes('world')] })]).execute(() => {
418+
expect(() => gloadUint64(0, 256)).toThrow('invalid scratch slot')
419+
})
420+
})
421+
})
422+
423+
describe('Block', async () => {
424+
it('should return the correct field value of the block', async () => {
425+
const index = 42
426+
const seed = 123
427+
const timestamp = 1234567890
428+
ctx.ledger.setBlock(index, seed, timestamp)
429+
const seedResult = op.btoi(Block.blkSeed(Uint64(index)))
430+
const timestampResult = Block.blkTimestamp(Uint64(index))
431+
432+
expect(seedResult).toEqual(Uint64(seed))
433+
expect(timestampResult).toEqual(Uint64(timestamp))
434+
})
435+
it('should throw error if the block is not set', async () => {
436+
const index = 42
437+
expect(() => Block.blkSeed(Uint64(index))).toThrow('Block 42 not set')
438+
expect(() => Block.blkTimestamp(Uint64(index))).toThrow('Block 42 not set')
439+
})
440+
})
379441
})

0 commit comments

Comments
 (0)