Skip to content

Commit

Permalink
Fix/extract opcodes (#666)
Browse files Browse the repository at this point in the history
* fix bug parameter in extract opcode should be bigint

* update CHANGLOG.md

* remove unused space

* slight updated
  • Loading branch information
vuvoth authored May 4, 2022
1 parent e09b76e commit 7de34d5
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ recommended to use the method from `Deployer` rather than the function dirrectly
- Approval program and clear propram should throw error if they are mismatch version. Fixed in [#620](https://github.com/scale-it/algo-builder/pull/620)
- Allow token to be empty.
- Throw error when issue inner transactions in clear program. Fixed in [#667](https://github.com/scale-it/algo-builder/pull/667).
- Parameters in `extract*` opcodes can greater than uint8. Fixed in [#666](https://github.com/scale-it/algo-builder/pull/666).

### Infrastructure

Expand Down
6 changes: 3 additions & 3 deletions packages/runtime/src/interpreter/opcode-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3575,8 +3575,8 @@ export class Extract3 extends Op {

execute(stack: TEALStack): void {
this.assertMinStackLen(stack, 3, this.line);
const length = this.assertUInt8(stack.pop(), this.line);
const start = this.assertUInt8(stack.pop(), this.line);
const length = Number(this.assertBigInt(stack.pop(), this.line));
const start = Number(this.assertBigInt(stack.pop(), this.line));
const array = this.assertBytes(stack.pop(), this.line);

stack.push(this.opExtractImpl(array, start, length));
Expand Down Expand Up @@ -3611,7 +3611,7 @@ class ExtractUintN extends Op {

execute(stack: TEALStack): void {
this.assertMinStackLen(stack, 2, this.line);
const start = this.assertUInt8(stack.pop(), this.line);
const start = Number(this.assertBigInt(stack.pop(), this.line));
const array = this.assertBytes(stack.pop(), this.line);

const sliced = this.opExtractImpl(array, start, this.extractBytes); // extract n bytes
Expand Down
63 changes: 47 additions & 16 deletions packages/runtime/test/src/interpreter/opcode-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5650,6 +5650,7 @@ describe("Teal Opcodes", function () {

describe("Tealv5: Extract opcodes", () => {
const stack = new Stack<StackElem>();
const longByte = parsing.stringToBytes("a".repeat(400));

it("extract", () => {
stack.push(new Uint8Array([12, 23, 3, 2, 23, 43, 43, 12]));
Expand All @@ -5665,6 +5666,13 @@ describe("Teal Opcodes", function () {

assert.deepEqual(stack.pop(), new Uint8Array([23, 2, 4]));

// big bytes(length = 400)
stack.push(longByte);
op = new Extract(["300", "10"], 1);
op.execute(stack);

assert.deepEqual(stack.pop(), parsing.stringToBytes("a".repeat(10)));

stack.push(new Uint8Array([12, 23]));
op = new Extract(["1", "10"], 1);

Expand All @@ -5677,67 +5685,90 @@ describe("Teal Opcodes", function () {
});

it("extract3", () => {
const op = new Extract3([], 1);

stack.push(new Uint8Array([12, 23, 3, 2, 23, 43, 43, 12]));
stack.push(1n);
stack.push(3n);
let op = new Extract3([], 1);
op.execute(stack);

assert.deepEqual(stack.pop(), new Uint8Array([23, 3, 2]));

stack.push(longByte);
stack.push(300n);
stack.push(10n);
op.execute(stack);
assert.deepEqual(stack.pop(), parsing.stringToBytes("a".repeat(10)));

stack.push(new Uint8Array([12, 23]));
stack.push(1n);
stack.push(10n);
op = new Extract3([], 1);

expectRuntimeError(() => op.execute(stack), RUNTIME_ERRORS.TEAL.EXTRACT_RANGE_ERROR);
});

it("extract_uint16", () => {
const op = new ExtractUint16([], 1);
let expected: bigint;

stack.push(new Uint8Array([1, 2, 3, 4, 5]));
stack.push(2n);

const op = new ExtractUint16([], 1);
op.execute(stack);
expected = bigEndianBytesToBigInt(new Uint8Array([3, 4]));
assert.equal(stack.pop(), expected);

const expected = bigEndianBytesToBigInt(new Uint8Array([3, 4]));
// long byte
stack.push(longByte);
stack.push(300n);
op.execute(stack);
expected = bigEndianBytesToBigInt(new Uint8Array([97, 97]));
assert.equal(stack.pop(), expected);

// throw error
stack.push(new Uint8Array([1, 2, 3, 4, 5]));
stack.push(4n);

expectRuntimeError(() => op.execute(stack), RUNTIME_ERRORS.TEAL.EXTRACT_RANGE_ERROR);
});

it("extract_uint32", () => {
const op = new ExtractUint32([], 1);
let expected: bigint;

stack.push(new Uint8Array([1, 2, 3, 4, 5]));
stack.push(1n);

const op = new ExtractUint32([], 1);
op.execute(stack);
expected = bigEndianBytesToBigInt(new Uint8Array([2, 3, 4, 5]));
assert.equal(stack.pop(), expected);

const expected = bigEndianBytesToBigInt(new Uint8Array([2, 3, 4, 5]));
// long bytes
stack.push(longByte);
stack.push(300n);
op.execute(stack);
expected = bigEndianBytesToBigInt(new Uint8Array([97, 97, 97, 97]));
assert.equal(stack.pop(), expected);

// throw error
stack.push(new Uint8Array([1, 2, 3, 4, 5]));
stack.push(4n);

expectRuntimeError(() => op.execute(stack), RUNTIME_ERRORS.TEAL.EXTRACT_RANGE_ERROR);
});

it("extract_uint64", () => {
const op = new ExtractUint64([], 1);
let expected: bigint;

stack.push(new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]));
stack.push(2n);

const op = new ExtractUint64([], 1);
op.execute(stack);
expected = bigEndianBytesToBigInt(new Uint8Array([3, 4, 5, 6, 7, 8, 9, 10]));
assert.equal(stack.pop(), expected);

const expected = bigEndianBytesToBigInt(new Uint8Array([3, 4, 5, 6, 7, 8, 9, 10]));
stack.push(longByte);
stack.push(300n);
op.execute(stack);
expected = bigEndianBytesToBigInt(new Uint8Array([97, 97, 97, 97, 97, 97, 97, 97]));
assert.equal(stack.pop(), expected);

stack.push(new Uint8Array([1, 2, 3, 4, 5]));
stack.push(8n);

expectRuntimeError(() => op.execute(stack), RUNTIME_ERRORS.TEAL.EXTRACT_RANGE_ERROR);
});
});
Expand Down

0 comments on commit 7de34d5

Please sign in to comment.