From 475673ffd13438138f744f56893e809073843c62 Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Wed, 19 Oct 2022 17:57:58 +0200 Subject: [PATCH 01/24] draft implementation for block opcode --- .../runtime/src/interpreter/interpreter.ts | 20 +++++++ .../runtime/src/interpreter/opcode-list.ts | 54 +++++++++++++++++-- packages/runtime/src/interpreter/opcode.ts | 3 +- packages/runtime/src/lib/constants.ts | 2 + .../test/src/interpreter/opcode-list.ts | 22 ++++++++ 5 files changed, 95 insertions(+), 6 deletions(-) diff --git a/packages/runtime/src/interpreter/interpreter.ts b/packages/runtime/src/interpreter/interpreter.ts index 1ac06666f..a53b72aea 100644 --- a/packages/runtime/src/interpreter/interpreter.ts +++ b/packages/runtime/src/interpreter/interpreter.ts @@ -17,6 +17,7 @@ import { DEFAULT_STACK_ELEM, LOGIC_SIG_MAX_COST, MaxTEALVersion, + MaxTxnLife, MinVersionSupportC2CCall, TransactionTypeEnum, } from "../lib/constants"; @@ -595,4 +596,23 @@ export class Interpreter { } return result; } + + //TODO:add description + assertRoundIsAvailable(round: number): void { + let firstAvail = this.runtime.ctx.tx.lv - MaxTxnLife - 1; + if (firstAvail > this.runtime.ctx.tx.lv || firstAvail === 0) { + // early in chain's life + firstAvail = 1; + } + //TODO: what happends if FirstValid is undefined? + let lastAvail = this.runtime.ctx.tx.fv === undefined ? 0 : this.runtime.ctx.tx.fv - 1; + if (this.runtime.ctx.tx.fv === undefined || lastAvail > this.runtime.ctx.tx.fv) { + // txn had a 0 in FirstValid + lastAvail = 0; // So nothing will be available + } + if (firstAvail > round || round > lastAvail) { + throw new Error(); + // throw error ("round %d is not available. It's outside [%d-%d]", r, firstAvail, lastAvail) + } + } } diff --git a/packages/runtime/src/interpreter/opcode-list.ts b/packages/runtime/src/interpreter/opcode-list.ts index c44abfd3a..288b859a0 100644 --- a/packages/runtime/src/interpreter/opcode-list.ts +++ b/packages/runtime/src/interpreter/opcode-list.ts @@ -84,7 +84,8 @@ import { } from "../types"; import { Interpreter } from "./interpreter"; import { Op } from "./opcode"; -const bn254 = require("rustbn.js");// eslint-disable-line @typescript-eslint/no-var-requires +const bn254 = require("rustbn.js"); // eslint-disable-line @typescript-eslint/no-var-requires +import { randomBytes } from "crypto"; // Opcodes reference link: https://developer.algorand.org/docs/reference/teal/opcodes/ @@ -4354,10 +4355,10 @@ export class ITxnSubmit extends Op { const signedTransactions: algosdk.SignedTransaction[] = execParams.map((txnParam) => types.isExecParams(txnParam) ? { - sig: Buffer.alloc(5), - sgnr: Buffer.from(algosdk.decodeAddress(contractAddress).publicKey), - txn: webTx.mkTransaction(txnParam, mockSuggestedParams(txnParam.payFlags, 1)), - } + sig: Buffer.alloc(5), + sgnr: Buffer.from(algosdk.decodeAddress(contractAddress).publicKey), + txn: webTx.mkTransaction(txnParam, mockSuggestedParams(txnParam.payFlags, 1)), + } : txnParam ); this.interpreter.runtime.ctx.processTransactions(signedTransactions); @@ -5210,6 +5211,7 @@ export class Json_ref extends Op { return this.computeCost(); } } +//TODO:add description export class Bn254Add extends Op { readonly line: number; /** @@ -5233,6 +5235,7 @@ export class Bn254Add extends Op { return this.computeCost(); } } +//TODO:add description export class Bn254ScalarMul extends Op { readonly line: number; /** @@ -5256,6 +5259,7 @@ export class Bn254ScalarMul extends Op { return this.computeCost(); } } +//TODO:add description export class Bn254Pairing extends Op { readonly line: number; /** @@ -5280,3 +5284,43 @@ export class Bn254Pairing extends Op { return this.computeCost(); } } +//TODO:add description +export class Block extends Op { + readonly line: number; + readonly field: string; + readonly interpreter: Interpreter; + //TODO:add description + /** + * @param args + * @param line line number in TEAL file + */ + constructor(args: string[], line: number, interpreter: Interpreter) { + super(); + assertLen(args.length, 1, line); + const argument = args[0]; + if (argument === "BlkSeed" || argument === "BlkTimestamp") { + this.field = argument; + } else { + throw new Error(); + //throw an error, unknown field + } + this.line = line; + this.interpreter = interpreter; + } + execute(stack: TEALStack): number { + this.assertMinStackLen(stack, 1, this.line); + const round = this.assertBigInt(stack.pop(), this.line); + this.interpreter.assertRoundIsAvailable(Number(round)); + let result: StackElem; + if (this.field === "BlkSeed") { + //mock the seed by generating a 32 bytes long psuedo-random + result = randomBytes(20); + } else { + //"BlkTimestamp" + //seconds since epoch + result = BigInt(Math.round(new Date().getTime() / 1000)); + } + stack.push(result); + return this.computeCost(); + } +} diff --git a/packages/runtime/src/interpreter/opcode.ts b/packages/runtime/src/interpreter/opcode.ts index 104424d6d..421f3108b 100644 --- a/packages/runtime/src/interpreter/opcode.ts +++ b/packages/runtime/src/interpreter/opcode.ts @@ -193,13 +193,14 @@ export abstract class Op { * @param index Index * @param line line number in TEAL file */ - assert64BitIndex(index: bigint, line: number): void { + assert64BitIndex(index: bigint, line: number): bigint { if (index > MAX_UINT6) { throw new RuntimeError(RUNTIME_ERRORS.TEAL.SET_BIT_INDEX_ERROR, { index: index, line: line, }); } + return index; } /** diff --git a/packages/runtime/src/lib/constants.ts b/packages/runtime/src/lib/constants.ts index c52247210..dc52439f1 100644 --- a/packages/runtime/src/lib/constants.ts +++ b/packages/runtime/src/lib/constants.ts @@ -56,6 +56,8 @@ export const MAX_LOCAL_SCHEMA_ENTRIES = 16; export const MAX_INPUT_BYTE_LEN = 64; export const MAX_OUTPUT_BYTE_LEN = 128; +export const MaxTxnLife = 1000; //TODO:add description + export const ZERO_ADDRESS = new Uint8Array(32); export const ZERO_ADDRESS_STR = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ"; const zeroUint64 = 0n; diff --git a/packages/runtime/test/src/interpreter/opcode-list.ts b/packages/runtime/test/src/interpreter/opcode-list.ts index ad3370104..bc70482b6 100644 --- a/packages/runtime/test/src/interpreter/opcode-list.ts +++ b/packages/runtime/test/src/interpreter/opcode-list.ts @@ -45,6 +45,7 @@ import { BitwiseNot, BitwiseOr, BitwiseXor, + Block, Bn254Add, Bn254Pairing, Bn254ScalarMul, @@ -7563,4 +7564,25 @@ describe("Teal Opcodes", function () { assert.equal(expectedResult, stack.pop()); }); }); + describe.only("block op", function () { + const stack = new Stack(); + let interpreter: Interpreter; + this.beforeEach(function () { + interpreter = new Interpreter(); + interpreter.runtime = new Runtime([]); + interpreter.runtime.ctx.tx = TXN_OBJ; + interpreter.tealVersion = MaxTEALVersion; // set tealversion to latest (to support all tx fields) + }); + + it("Should fail when accesing two behind FirstVaild because LastValid is 1000 after", function () { + stack.push(BigInt(TXN_OBJ.fv - 2)); + const op = new Block(["BlkTimestamp"], 1, interpreter); + assert.throws(() => op.execute(stack)); + }); + it("Should allow to acces two behind FirstValid", function () { + stack.push(BigInt(TXN_OBJ.fv - 1)); + const op = new Block(["BlkTimestamp"], 1, interpreter); + assert.doesNotThrow(() => op.execute(stack)); + }); + }); }); From cf2889f63c65bbd3418f69d11efcf73e8b672606 Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Wed, 19 Oct 2022 21:17:37 +0200 Subject: [PATCH 02/24] better way to mock the seed and timestamp --- packages/runtime/src/interpreter/opcode-list.ts | 9 ++++++--- packages/runtime/src/lib/constants.ts | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/runtime/src/interpreter/opcode-list.ts b/packages/runtime/src/interpreter/opcode-list.ts index 288b859a0..c0a4f01f7 100644 --- a/packages/runtime/src/interpreter/opcode-list.ts +++ b/packages/runtime/src/interpreter/opcode-list.ts @@ -29,6 +29,7 @@ import { ALGORAND_MAX_LOGS_LENGTH, AppParamDefined, AssetParamMap, + BlockFinalizationTime, GlobalFields, ITxArrFields, json_refTypes, @@ -86,6 +87,7 @@ import { Interpreter } from "./interpreter"; import { Op } from "./opcode"; const bn254 = require("rustbn.js"); // eslint-disable-line @typescript-eslint/no-var-requires import { randomBytes } from "crypto"; +import * as base32 from "hi-base32"; // Opcodes reference link: https://developer.algorand.org/docs/reference/teal/opcodes/ @@ -5314,11 +5316,12 @@ export class Block extends Op { let result: StackElem; if (this.field === "BlkSeed") { //mock the seed by generating a 32 bytes long psuedo-random - result = randomBytes(20); + result = randomBytes(32); } else { //"BlkTimestamp" - //seconds since epoch - result = BigInt(Math.round(new Date().getTime() / 1000)); + //seconds since epoch - rounds, assuming one round(block) = 2.5s truncated to 2s (BigInt) + result = + BigInt(Math.round(new Date().getTime() / 1000)) - round * BigInt(BlockFinalizationTime); } stack.push(result); return this.computeCost(); diff --git a/packages/runtime/src/lib/constants.ts b/packages/runtime/src/lib/constants.ts index dc52439f1..c262f8c1d 100644 --- a/packages/runtime/src/lib/constants.ts +++ b/packages/runtime/src/lib/constants.ts @@ -57,6 +57,7 @@ export const MAX_INPUT_BYTE_LEN = 64; export const MAX_OUTPUT_BYTE_LEN = 128; export const MaxTxnLife = 1000; //TODO:add description +export const BlockFinalizationTime = 2.5; // block finalization time in seconds export const ZERO_ADDRESS = new Uint8Array(32); export const ZERO_ADDRESS_STR = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ"; From 8d4e7c88874a17e7e2688a8c3bfbfeddda42f5c1 Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Thu, 20 Oct 2022 22:30:46 +0200 Subject: [PATCH 03/24] changing the constans --- packages/runtime/src/interpreter/opcode-list.ts | 3 +-- packages/runtime/src/lib/constants.ts | 2 +- .../runtime/test/src/interpreter/opcode-list.ts | 13 +++++++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/runtime/src/interpreter/opcode-list.ts b/packages/runtime/src/interpreter/opcode-list.ts index c0a4f01f7..c373473ed 100644 --- a/packages/runtime/src/interpreter/opcode-list.ts +++ b/packages/runtime/src/interpreter/opcode-list.ts @@ -5320,8 +5320,7 @@ export class Block extends Op { } else { //"BlkTimestamp" //seconds since epoch - rounds, assuming one round(block) = 2.5s truncated to 2s (BigInt) - result = - BigInt(Math.round(new Date().getTime() / 1000)) - round * BigInt(BlockFinalizationTime); + result = BigInt(Math.round(new Date().getTime() / 1000)) - round * BlockFinalizationTime; } stack.push(result); return this.computeCost(); diff --git a/packages/runtime/src/lib/constants.ts b/packages/runtime/src/lib/constants.ts index c262f8c1d..600687404 100644 --- a/packages/runtime/src/lib/constants.ts +++ b/packages/runtime/src/lib/constants.ts @@ -57,7 +57,7 @@ export const MAX_INPUT_BYTE_LEN = 64; export const MAX_OUTPUT_BYTE_LEN = 128; export const MaxTxnLife = 1000; //TODO:add description -export const BlockFinalizationTime = 2.5; // block finalization time in seconds +export const BlockFinalizationTime = 2n; // block finalization time in seconds truncated down export const ZERO_ADDRESS = new Uint8Array(32); export const ZERO_ADDRESS_STR = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ"; diff --git a/packages/runtime/test/src/interpreter/opcode-list.ts b/packages/runtime/test/src/interpreter/opcode-list.ts index bc70482b6..2d89edc78 100644 --- a/packages/runtime/test/src/interpreter/opcode-list.ts +++ b/packages/runtime/test/src/interpreter/opcode-list.ts @@ -7567,6 +7567,7 @@ describe("Teal Opcodes", function () { describe.only("block op", function () { const stack = new Stack(); let interpreter: Interpreter; + const LAST_VALID = 259820n; this.beforeEach(function () { interpreter = new Interpreter(); interpreter.runtime = new Runtime([]); @@ -7584,5 +7585,17 @@ describe("Teal Opcodes", function () { const op = new Block(["BlkTimestamp"], 1, interpreter); assert.doesNotThrow(() => op.execute(stack)); }); + it("Should return two different seeds for to different rounds", function () { + const op = new Block(["BlkTimestamp"], 1, interpreter); + //first round + stack.push(LAST_VALID - 2n); + op.execute(stack); + const seedRound1 = stack.pop(); + //second round + stack.push(LAST_VALID - 3n); + op.execute(stack); + const seedRound2 = stack.pop(); + assert.notEqual(seedRound1, seedRound2); + }); }); }); From 34dcac2fbc792038c0ec12e16bb628b6c129ad5b Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Wed, 26 Oct 2022 19:46:52 +0200 Subject: [PATCH 04/24] add blocks to runtime --- packages/runtime/src/errors/errors-list.ts | 12 ++++++ .../runtime/src/interpreter/opcode-list.ts | 10 ++--- packages/runtime/src/runtime.ts | 37 ++++++++++++++++++- packages/runtime/src/types.ts | 6 +++ .../test/src/interpreter/opcode-list.ts | 2 +- 5 files changed, 59 insertions(+), 8 deletions(-) diff --git a/packages/runtime/src/errors/errors-list.ts b/packages/runtime/src/errors/errors-list.ts index 81a00eb54..7f205f7b3 100644 --- a/packages/runtime/src/errors/errors-list.ts +++ b/packages/runtime/src/errors/errors-list.ts @@ -596,6 +596,18 @@ const runtimeGeneralErrors = { description: "Provided multisignature is invalid and was not able to authenticate the transaction", }, + PRODUCE_BLOCK: { + number: 1322, + message: "Produce block", + title: "Produce block", + description: "Runtime failed while trying to produce new block", + }, + INVALID_BLOCK: { + number: 1323, + message: "Invalid block", + title: "Invalid block", + description: "Provided round does not correspond to any existing block", + } }; const transactionErrors = { diff --git a/packages/runtime/src/interpreter/opcode-list.ts b/packages/runtime/src/interpreter/opcode-list.ts index c373473ed..3263c133a 100644 --- a/packages/runtime/src/interpreter/opcode-list.ts +++ b/packages/runtime/src/interpreter/opcode-list.ts @@ -5311,16 +5311,16 @@ export class Block extends Op { } execute(stack: TEALStack): number { this.assertMinStackLen(stack, 1, this.line); - const round = this.assertBigInt(stack.pop(), this.line); - this.interpreter.assertRoundIsAvailable(Number(round)); + const round = Number(this.assertBigInt(stack.pop(), this.line)); + this.interpreter.assertRoundIsAvailable(round); + const block = this.interpreter.runtime.getBlock(round); let result: StackElem; if (this.field === "BlkSeed") { - //mock the seed by generating a 32 bytes long psuedo-random - result = randomBytes(32); + result = block.seed; } else { //"BlkTimestamp" //seconds since epoch - rounds, assuming one round(block) = 2.5s truncated to 2s (BigInt) - result = BigInt(Math.round(new Date().getTime() / 1000)) - round * BlockFinalizationTime; + result = block.timestamp; } stack.push(result); return this.computeCost(); diff --git a/packages/runtime/src/runtime.ts b/packages/runtime/src/runtime.ts index 8e12a1ab2..ac4dbc579 100644 --- a/packages/runtime/src/runtime.ts +++ b/packages/runtime/src/runtime.ts @@ -7,9 +7,10 @@ import algosdk, { SignedTransaction, Transaction, } from "algosdk"; -import { exec } from "child_process"; +import { randomBytes } from "crypto"; import cloneDeep from "lodash.clonedeep"; import nacl from "tweetnacl"; +import { bigint, map } from "zod"; import { AccountStore, defaultSDKAccounts, RuntimeAccount } from "./account"; import { Ctx } from "./ctx"; @@ -20,6 +21,7 @@ import { compareArray } from "./lib/compare"; import { ALGORAND_ACCOUNT_MIN_BALANCE, ALGORAND_MAX_TX_ARRAY_LEN, + BlockFinalizationTime, MAX_APP_PROGRAM_COST, TransactionTypeEnum, ZERO_ADDRESS_STR, @@ -35,6 +37,7 @@ import { ASADeploymentFlags, ASAInfo, AssetHoldingM, + Block, Context, EncTx, ExecutionMode, @@ -76,6 +79,7 @@ export class Runtime { appCounter: ALGORAND_MAX_TX_ARRAY_LEN, // initialize app counter with 8 assetCounter: ALGORAND_MAX_TX_ARRAY_LEN, // initialize asset counter with 8 txReceipts: new Map(), // receipt of each transaction, i.e map of {txID: txReceipt} + blocks: new Map(), }; this._defaultAccounts = this._setupDefaultAccounts(); @@ -88,7 +92,8 @@ export class Runtime { // context for interpreter this.ctx = new Ctx(cloneDeep(this.store), {}, [], [], this); - this.round = 2; + this.round = 1; + this.produceBlock(); this.timestamp = 1; } @@ -1162,4 +1167,32 @@ export class Runtime { sendTxAndWait(transactions: SignedTransaction[]): TxnReceipt[] { return this.executeTx(transactions); } + + produceBlock() { + let timestamp: bigint | undefined; + let seed: Uint8Array | undefined; + if (this.store.blocks.size === 0) { //create genesis block + seed = randomBytes(32); + timestamp = BigInt(Math.round(new Date().getTime() / 1000)); + } else { //add another block + const lastBlock = this.store.blocks.get(this.round); + if (lastBlock !== undefined) { + seed = randomBytes(32); + timestamp = lastBlock.timestamp + 4n; + this.round += 1;// we move to new a new round + } + } + if (timestamp !== undefined && seed !== undefined) { + this.store.blocks.set(this.round, { timestamp, seed }); + } + throw new RuntimeError(RUNTIME_ERRORS.GENERAL.PRODUCE_BLOCK); + } + + getBlock(round: number): Block { + const block = cloneDeep(this.store.blocks.get(round)); + if (block !== undefined) { + return block; + } + throw new RuntimeError(RUNTIME_ERRORS.GENERAL.INVALID_BLOCK); + } } diff --git a/packages/runtime/src/types.ts b/packages/runtime/src/types.ts index 8fe1c73e0..19691d767 100644 --- a/packages/runtime/src/types.ts +++ b/packages/runtime/src/types.ts @@ -102,6 +102,7 @@ export interface State { appCounter: number; assetCounter: number; txReceipts: Map; // map of {txID: txReceipt} + blocks: Map, // map of{round, block} } export interface DeployedAssetInfo { @@ -432,3 +433,8 @@ export interface AppInfoReceipt extends DeployedAssetInfoReceipt { logs?: Uint8Array[]; gas?: number; } + +export interface Block { + timestamp: bigint; //uint64 + seed: Uint8Array; //[]byte +} diff --git a/packages/runtime/test/src/interpreter/opcode-list.ts b/packages/runtime/test/src/interpreter/opcode-list.ts index 2d89edc78..242be0085 100644 --- a/packages/runtime/test/src/interpreter/opcode-list.ts +++ b/packages/runtime/test/src/interpreter/opcode-list.ts @@ -7575,7 +7575,7 @@ describe("Teal Opcodes", function () { interpreter.tealVersion = MaxTEALVersion; // set tealversion to latest (to support all tx fields) }); - it("Should fail when accesing two behind FirstVaild because LastValid is 1000 after", function () { + it.only("Should fail when accesing two behind FirstVaild because LastValid is 1000 after", function () { stack.push(BigInt(TXN_OBJ.fv - 2)); const op = new Block(["BlkTimestamp"], 1, interpreter); assert.throws(() => op.execute(stack)); From 1cdba96e0faad7003c49f00e12cd41ffe07c567e Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Thu, 27 Oct 2022 19:12:06 +0200 Subject: [PATCH 05/24] Add block to runtime; test scenario; block opcode --- packages/runtime/package.json | 2 + .../runtime/src/interpreter/interpreter.ts | 13 +++-- .../runtime/src/interpreter/opcode-list.ts | 14 ++++-- packages/runtime/src/runtime.ts | 34 +++++++++++--- .../test/src/interpreter/opcode-list.ts | 47 +++++++++++++++---- yarn.lock | 16 +++++++ 6 files changed, 101 insertions(+), 25 deletions(-) diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 5abaf4078..bc2d49dab 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -34,9 +34,11 @@ "dependencies": { "@algo-builder/web": "workspace:*", "@nodelib/fs.walk": "^1.2.8", + "@types/crypto-js": "^4.1.1", "@types/json-bigint": "^1.0.1", "algosdk": "^1.19.0", "chalk": "^4.1.2", + "crypto-js": "^4.1.1", "debug": "^4.3.4", "elliptic": "^6.5.4", "hi-base32": "^0.5.1", diff --git a/packages/runtime/src/interpreter/interpreter.ts b/packages/runtime/src/interpreter/interpreter.ts index a53b72aea..7ddca8334 100644 --- a/packages/runtime/src/interpreter/interpreter.ts +++ b/packages/runtime/src/interpreter/interpreter.ts @@ -171,7 +171,7 @@ export class Interpreter { if ( txAccounts?.find((buff) => compareArray(Uint8Array.from(buff), accountPk)) !== - undefined || + undefined || compareArray(accountPk, Uint8Array.from(this.runtime.ctx.tx.snd)) || // since tealv5, currentApplicationAddress is also allowed (directly) compareArray(accountPk, decodeAddress(getApplicationAddress(appID)).publicKey) || @@ -597,21 +597,26 @@ export class Interpreter { return result; } - //TODO:add description + /** + * This functions checks if the requested round is avaiable to access. If it is + * not throws an Error + * @param round: round number + * @returns void + */ assertRoundIsAvailable(round: number): void { let firstAvail = this.runtime.ctx.tx.lv - MaxTxnLife - 1; if (firstAvail > this.runtime.ctx.tx.lv || firstAvail === 0) { // early in chain's life firstAvail = 1; } - //TODO: what happends if FirstValid is undefined? let lastAvail = this.runtime.ctx.tx.fv === undefined ? 0 : this.runtime.ctx.tx.fv - 1; if (this.runtime.ctx.tx.fv === undefined || lastAvail > this.runtime.ctx.tx.fv) { // txn had a 0 in FirstValid lastAvail = 0; // So nothing will be available } if (firstAvail > round || round > lastAvail) { - throw new Error(); + throw new Error("round is not available"); + //todo: add better error // throw error ("round %d is not available. It's outside [%d-%d]", r, firstAvail, lastAvail) } } diff --git a/packages/runtime/src/interpreter/opcode-list.ts b/packages/runtime/src/interpreter/opcode-list.ts index 3263c133a..98fb3cb81 100644 --- a/packages/runtime/src/interpreter/opcode-list.ts +++ b/packages/runtime/src/interpreter/opcode-list.ts @@ -5286,15 +5286,20 @@ export class Bn254Pairing extends Op { return this.computeCost(); } } -//TODO:add description + +/** + * Opcode: 0xd1 {uint8 block field} + * Stack: ..., A: uint64 → ..., any + * field F of block A. Fail unless A falls between txn.LastValid-1002 and txn.FirstValid (exclusive) +*/ export class Block extends Op { readonly line: number; readonly field: string; readonly interpreter: Interpreter; - //TODO:add description /** - * @param args + * @param args Expected arguments: [BlkSeed || BlkTimestamp] * @param line line number in TEAL file + * @param interpreter interpreter instance */ constructor(args: string[], line: number, interpreter: Interpreter) { super(); @@ -5303,8 +5308,7 @@ export class Block extends Op { if (argument === "BlkSeed" || argument === "BlkTimestamp") { this.field = argument; } else { - throw new Error(); - //throw an error, unknown field + throw new Error("Unknown Block field"); } this.line = line; this.interpreter = interpreter; diff --git a/packages/runtime/src/runtime.ts b/packages/runtime/src/runtime.ts index ac4dbc579..e672ba313 100644 --- a/packages/runtime/src/runtime.ts +++ b/packages/runtime/src/runtime.ts @@ -7,9 +7,11 @@ import algosdk, { SignedTransaction, Transaction, } from "algosdk"; -import { randomBytes } from "crypto"; +import MD5 from "crypto-js/md5"; +// import { randomBytes } from "crypto"; import cloneDeep from "lodash.clonedeep"; import nacl from "tweetnacl"; +import { hash } from "tweetnacl-ts"; import { bigint, map } from "zod"; import { AccountStore, defaultSDKAccounts, RuntimeAccount } from "./account"; @@ -92,8 +94,8 @@ export class Runtime { // context for interpreter this.ctx = new Ctx(cloneDeep(this.store), {}, [], [], this); - this.round = 1; - this.produceBlock(); + this.round = 258820; + this.populateChain(this.round); this.timestamp = 1; } @@ -1168,26 +1170,34 @@ export class Runtime { return this.executeTx(transactions); } + /** + * Produces new block and adds it to a Map where the keys are block numbers + */ produceBlock() { let timestamp: bigint | undefined; let seed: Uint8Array | undefined; if (this.store.blocks.size === 0) { //create genesis block - seed = randomBytes(32); + seed = nacl.randomBytes(32); timestamp = BigInt(Math.round(new Date().getTime() / 1000)); } else { //add another block const lastBlock = this.store.blocks.get(this.round); if (lastBlock !== undefined) { - seed = randomBytes(32); + seed = new TextEncoder().encode(MD5(lastBlock.seed.toString()).toString()); timestamp = lastBlock.timestamp + 4n; this.round += 1;// we move to new a new round } } if (timestamp !== undefined && seed !== undefined) { this.store.blocks.set(this.round, { timestamp, seed }); - } + } else { throw new RuntimeError(RUNTIME_ERRORS.GENERAL.PRODUCE_BLOCK); + } } - + /** + * Returns a requested Block object. If it does not exist on chain throws an error + * @param round block number + * @returns Block + */ getBlock(round: number): Block { const block = cloneDeep(this.store.blocks.get(round)); if (block !== undefined) { @@ -1195,4 +1205,14 @@ export class Runtime { } throw new RuntimeError(RUNTIME_ERRORS.GENERAL.INVALID_BLOCK); } + /** + * Populates chain from first block to round number block (Produces N rounds) + * @param round current round number + */ + populateChain(round:number) { + this.round = 1 + for(let blockN = 1; blockN<=round; blockN++){ + this.produceBlock(); + } + } } diff --git a/packages/runtime/test/src/interpreter/opcode-list.ts b/packages/runtime/test/src/interpreter/opcode-list.ts index 242be0085..221f902da 100644 --- a/packages/runtime/test/src/interpreter/opcode-list.ts +++ b/packages/runtime/test/src/interpreter/opcode-list.ts @@ -11,8 +11,10 @@ import algosdk, { import { assert } from "chai"; import { ec as EC } from "elliptic"; import { sha512_256 } from "js-sha512"; +import cloneDeep from "lodash.clonedeep"; import { describe } from "mocha"; import nacl from "tweetnacl"; +import { isGeneratorFunction } from "util/types"; import { ExecutionMode } from "../../../build/types"; import { AccountStore } from "../../../src/account"; @@ -7564,38 +7566,65 @@ describe("Teal Opcodes", function () { assert.equal(expectedResult, stack.pop()); }); }); - describe.only("block op", function () { + describe("Block opcode", function () { const stack = new Stack(); let interpreter: Interpreter; - const LAST_VALID = 259820n; + const FIRST_VALID = 258820n; this.beforeEach(function () { interpreter = new Interpreter(); interpreter.runtime = new Runtime([]); - interpreter.runtime.ctx.tx = TXN_OBJ; + interpreter.runtime.ctx.tx = cloneDeep(TXN_OBJ); interpreter.tealVersion = MaxTEALVersion; // set tealversion to latest (to support all tx fields) }); - it.only("Should fail when accesing two behind FirstVaild because LastValid is 1000 after", function () { - stack.push(BigInt(TXN_OBJ.fv - 2)); + it("Should fail when accesing two behind FirstVaild because LastValid is 1000 after", function () { + stack.push(BigInt(FIRST_VALID - 2n)); const op = new Block(["BlkTimestamp"], 1, interpreter); assert.throws(() => op.execute(stack)); }); - it("Should allow to acces two behind FirstValid", function () { - stack.push(BigInt(TXN_OBJ.fv - 1)); + + it("Should allow to acces two behind FirstValid if LastValid is 100 after", function () { + interpreter.runtime.ctx.tx.lv = Number(FIRST_VALID) + 100; + stack.push(BigInt(FIRST_VALID - 2n)); const op = new Block(["BlkTimestamp"], 1, interpreter); assert.doesNotThrow(() => op.execute(stack)); }); + it("Should return two different seeds for to different rounds", function () { + interpreter.runtime.ctx.tx.lv = Number(FIRST_VALID) + 100; const op = new Block(["BlkTimestamp"], 1, interpreter); //first round - stack.push(LAST_VALID - 2n); + stack.push(FIRST_VALID - 1n); op.execute(stack); const seedRound1 = stack.pop(); //second round - stack.push(LAST_VALID - 3n); + stack.push(FIRST_VALID - 2n); op.execute(stack); const seedRound2 = stack.pop(); assert.notEqual(seedRound1, seedRound2); }); + + it("Should fail when accesing block 0 even if last valid is low", function(){ + interpreter.runtime.ctx.tx.lv = 100; + interpreter.runtime.ctx.tx.fv = 5; + stack.push(0n); + const op = new Block(["BlkTimestamp"], 1, interpreter); + assert.throws(() => op.execute(stack)); + }); + + it("Should return seed for a block that is within boundries and exist", function(){ + stack.push(FIRST_VALID - 1n); + const op = new Block(["BlkSeed"], 1, interpreter); + op.execute(stack); + const result = stack.pop(); + assert.equal((result as Buffer).length, 32); + }); + + it("Should return correct cost", function(){ + stack.push(FIRST_VALID - 1n); + const op = new Block(["BlkSeed"], 1, interpreter); + const cost = op.execute(stack); + assert.equal(cost, 1); + }); }); }); diff --git a/yarn.lock b/yarn.lock index 0b90af6fd..0399e6890 100644 --- a/yarn.lock +++ b/yarn.lock @@ -63,6 +63,7 @@ __metadata: "@algo-builder/web": "workspace:*" "@nodelib/fs.walk": ^1.2.8 "@types/chai": ^4.3.0 + "@types/crypto-js": ^4.1.1 "@types/debug": ^4.1.7 "@types/elliptic": ^6.4.14 "@types/json-bigint": ^1.0.1 @@ -73,6 +74,7 @@ __metadata: algosdk: ^1.19.0 chai: ^4.3.6 chalk: ^4.1.2 + crypto-js: ^4.1.1 debug: ^4.3.4 elliptic: ^6.5.4 eslint: ^8.10.0 @@ -668,6 +670,13 @@ __metadata: languageName: node linkType: hard +"@types/crypto-js@npm:^4.1.1": + version: 4.1.1 + resolution: "@types/crypto-js@npm:4.1.1" + checksum: ea3d6a67b69f88baeb6af96004395903d2367a41bd5cd86306da23a44dd96589749495da50974a9b01bb5163c500764c8a33706831eade036bddae016417e3ea + languageName: node + linkType: hard + "@types/debug@npm:^4.1.7": version: 4.1.7 resolution: "@types/debug@npm:4.1.7" @@ -2152,6 +2161,13 @@ __metadata: languageName: unknown linkType: soft +"crypto-js@npm:^4.1.1": + version: 4.1.1 + resolution: "crypto-js@npm:4.1.1" + checksum: b3747c12ee3a7632fab3b3e171ea50f78b182545f0714f6d3e7e2858385f0f4101a15f2517e033802ce9d12ba50a391575ff4638c9de3dd9b2c4bc47768d5425 + languageName: node + linkType: hard + "dao@workspace:examples/dao": version: 0.0.0-use.local resolution: "dao@workspace:examples/dao" From 3fca2975d664b23df791718b54f6cb391c846f05 Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Thu, 27 Oct 2022 23:50:50 +0200 Subject: [PATCH 06/24] change defult value of round to 2000 --- packages/runtime/src/runtime.ts | 5 +---- packages/runtime/test/mocks/txn.ts | 4 ++-- packages/runtime/test/src/interpreter/opcode-list.ts | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/runtime/src/runtime.ts b/packages/runtime/src/runtime.ts index e672ba313..e9af9430d 100644 --- a/packages/runtime/src/runtime.ts +++ b/packages/runtime/src/runtime.ts @@ -11,8 +11,6 @@ import MD5 from "crypto-js/md5"; // import { randomBytes } from "crypto"; import cloneDeep from "lodash.clonedeep"; import nacl from "tweetnacl"; -import { hash } from "tweetnacl-ts"; -import { bigint, map } from "zod"; import { AccountStore, defaultSDKAccounts, RuntimeAccount } from "./account"; import { Ctx } from "./ctx"; @@ -23,7 +21,6 @@ import { compareArray } from "./lib/compare"; import { ALGORAND_ACCOUNT_MIN_BALANCE, ALGORAND_MAX_TX_ARRAY_LEN, - BlockFinalizationTime, MAX_APP_PROGRAM_COST, TransactionTypeEnum, ZERO_ADDRESS_STR, @@ -94,7 +91,7 @@ export class Runtime { // context for interpreter this.ctx = new Ctx(cloneDeep(this.store), {}, [], [], this); - this.round = 258820; + this.round = 2000; this.populateChain(this.round); this.timestamp = 1; } diff --git a/packages/runtime/test/mocks/txn.ts b/packages/runtime/test/mocks/txn.ts index 923c5160d..ff0325791 100644 --- a/packages/runtime/test/mocks/txn.ts +++ b/packages/runtime/test/mocks/txn.ts @@ -22,8 +22,8 @@ const txn_obj = { fee: 1000, amt: 20200, aamt: 100, - fv: 258820, - lv: 259820, + fv: 2000, + lv: 3000, note: Buffer.from("Note"), gen: "default-v1", gh: Buffer.from("default-v1"), diff --git a/packages/runtime/test/src/interpreter/opcode-list.ts b/packages/runtime/test/src/interpreter/opcode-list.ts index 221f902da..f13d89a67 100644 --- a/packages/runtime/test/src/interpreter/opcode-list.ts +++ b/packages/runtime/test/src/interpreter/opcode-list.ts @@ -7569,7 +7569,7 @@ describe("Teal Opcodes", function () { describe("Block opcode", function () { const stack = new Stack(); let interpreter: Interpreter; - const FIRST_VALID = 258820n; + const FIRST_VALID = 2000n; this.beforeEach(function () { interpreter = new Interpreter(); interpreter.runtime = new Runtime([]); From dc2045653d4b4daf15e5429b4f102ac0f4f35a41 Mon Sep 17 00:00:00 2001 From: sczembor <43810037+sczembor@users.noreply.github.com> Date: Fri, 28 Oct 2022 00:12:24 +0200 Subject: [PATCH 07/24] change finalisation time --- packages/runtime/src/lib/constants.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/runtime/src/lib/constants.ts b/packages/runtime/src/lib/constants.ts index 600687404..2f29920ac 100644 --- a/packages/runtime/src/lib/constants.ts +++ b/packages/runtime/src/lib/constants.ts @@ -56,8 +56,8 @@ export const MAX_LOCAL_SCHEMA_ENTRIES = 16; export const MAX_INPUT_BYTE_LEN = 64; export const MAX_OUTPUT_BYTE_LEN = 128; -export const MaxTxnLife = 1000; //TODO:add description -export const BlockFinalizationTime = 2n; // block finalization time in seconds truncated down +export const MaxTxnLife = 1000; +export const BlockFinalisationTime = 4n; // block finalisation time in seconds truncated down export const ZERO_ADDRESS = new Uint8Array(32); export const ZERO_ADDRESS_STR = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ"; From 1c4bb9c733cbc18a7ffa6d607615c2ffd69ab621 Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Fri, 28 Oct 2022 00:40:54 +0200 Subject: [PATCH 08/24] add enum; add proper error --- packages/runtime/src/errors/errors-list.ts | 6 ++++++ packages/runtime/src/interpreter/opcode-list.ts | 8 ++++---- packages/runtime/src/lib/constants.ts | 5 +++++ packages/runtime/src/runtime.ts | 4 ++-- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/runtime/src/errors/errors-list.ts b/packages/runtime/src/errors/errors-list.ts index 7f205f7b3..803941a84 100644 --- a/packages/runtime/src/errors/errors-list.ts +++ b/packages/runtime/src/errors/errors-list.ts @@ -456,6 +456,12 @@ maximun uint128`, description: "Maximum program length %maxAppProgramLen% exceeded. Use `ApprovalProgramPages` instead", }, + UNKNOWN_BLOCK_FIELD: { + number: 1067, + message: "Unknown block opcode field", + title: "Unknown field", + description: "Block opcode support only BlkTimestamp and BlkSeed field, got: %field", + } }; const runtimeGeneralErrors = { diff --git a/packages/runtime/src/interpreter/opcode-list.ts b/packages/runtime/src/interpreter/opcode-list.ts index a53b53c3b..c74fc2285 100644 --- a/packages/runtime/src/interpreter/opcode-list.ts +++ b/packages/runtime/src/interpreter/opcode-list.ts @@ -29,7 +29,6 @@ import { ALGORAND_MAX_LOGS_LENGTH, AppParamDefined, AssetParamMap, - BlockFinalizationTime, GlobalFields, ITxArrFields, json_refTypes, @@ -46,6 +45,7 @@ import { TransactionTypeEnum, TxArrFields, ZERO_ADDRESS, + blockFieldTypes, } from "../lib/constants"; import { addInnerTransaction, calculateInnerTxCredit, setInnerTxField } from "../lib/itxn"; import { bigintSqrt } from "../lib/math"; @@ -5304,10 +5304,10 @@ export class Block extends Op { super(); assertLen(args.length, 1, line); const argument = args[0]; - if (argument === "BlkSeed" || argument === "BlkTimestamp") { + if (argument === blockFieldTypes.BlkSeed|| argument === blockFieldTypes.BlkTimestamp) { this.field = argument; } else { - throw new Error("Unknown Block field"); + throw new RuntimeError(RUNTIME_ERRORS.TEAL.UNKNOWN_BLOCK_FIELD, {field: argument}); } this.line = line; this.interpreter = interpreter; @@ -5318,7 +5318,7 @@ export class Block extends Op { this.interpreter.assertRoundIsAvailable(round); const block = this.interpreter.runtime.getBlock(round); let result: StackElem; - if (this.field === "BlkSeed") { + if (this.field === blockFieldTypes.BlkSeed) { result = block.seed; } else { //"BlkTimestamp" diff --git a/packages/runtime/src/lib/constants.ts b/packages/runtime/src/lib/constants.ts index 2f29920ac..43e22d39f 100644 --- a/packages/runtime/src/lib/constants.ts +++ b/packages/runtime/src/lib/constants.ts @@ -520,6 +520,11 @@ export const json_refTypes = { JSONObject: "JSONObject", }; +export enum blockFieldTypes { + BlkTimestamp = "BlkTimestamp", + BlkSeed = "BlkSeed", +}; + export enum TxFieldEnum { FirstValidTime = "FirstValidTime", TypeEnum = "TypeEnum", diff --git a/packages/runtime/src/runtime.ts b/packages/runtime/src/runtime.ts index fb130a758..7bbd4c056 100644 --- a/packages/runtime/src/runtime.ts +++ b/packages/runtime/src/runtime.ts @@ -7,7 +7,6 @@ import algosdk, { SignedTransaction, Transaction, } from "algosdk"; - import MD5 from "crypto-js/md5"; import cloneDeep from "lodash.clonedeep"; import nacl from "tweetnacl"; @@ -21,6 +20,7 @@ import { compareArray } from "./lib/compare"; import { ALGORAND_ACCOUNT_MIN_BALANCE, ALGORAND_MAX_TX_ARRAY_LEN, + BlockFinalisationTime, MAX_APP_PROGRAM_COST, TransactionTypeEnum, ZERO_ADDRESS_STR, @@ -1180,7 +1180,7 @@ export class Runtime { const lastBlock = this.store.blocks.get(this.round); if (lastBlock !== undefined) { seed = new TextEncoder().encode(MD5(lastBlock.seed.toString()).toString()); - timestamp = lastBlock.timestamp + 4n; + timestamp = lastBlock.timestamp + BlockFinalisationTime; this.round += 1;// we move to new a new round } } From 4537e8723108f5886cab12a4965f69c803ded73a Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Fri, 28 Oct 2022 01:41:10 +0200 Subject: [PATCH 09/24] add tests for runtime functions --- packages/runtime/src/runtime.ts | 2 +- packages/runtime/test/src/runtime.ts | 30 +++++++++++++++++++++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/runtime/src/runtime.ts b/packages/runtime/src/runtime.ts index 7bbd4c056..2d6574f31 100644 --- a/packages/runtime/src/runtime.ts +++ b/packages/runtime/src/runtime.ts @@ -1206,7 +1206,7 @@ export class Runtime { * Populates chain from first block to round number block (Produces N rounds) * @param round current round number */ - populateChain(round:number) { + private populateChain(round:number) { this.round = 1 for(let blockN = 1; blockN<=round; blockN++){ this.produceBlock(); diff --git a/packages/runtime/test/src/runtime.ts b/packages/runtime/test/src/runtime.ts index 9d53d8f7b..d9ca7d990 100644 --- a/packages/runtime/test/src/runtime.ts +++ b/packages/runtime/test/src/runtime.ts @@ -1,13 +1,12 @@ import { types } from "@algo-builder/web"; -import { ExecParams, SignType, TransactionType } from "@algo-builder/web/build/types"; import algosdk, { LogicSigAccount, Transaction } from "algosdk"; -import { assert } from "chai"; +import { assert, expect } from "chai"; import sinon from "sinon"; import { getProgram } from "../../src"; import { AccountStore } from "../../src/account"; import { RUNTIME_ERRORS } from "../../src/errors/errors-list"; -import { ASSET_CREATION_FEE } from "../../src/lib/constants"; +import { ASSET_CREATION_FEE, BlockFinalisationTime } from "../../src/lib/constants"; import { mockSuggestedParams } from "../../src/mock/tx"; import { Runtime } from "../../src/runtime"; import { AccountStoreI } from "../../src/types"; @@ -1442,3 +1441,28 @@ describe("Helper functions", function () { }); }); }); +describe.only("Funtions related to runtime chain", function(){ + let runtime: Runtime; + + this.beforeEach(function(){ + runtime = new Runtime([]); + }) + + it("Should return current block", function(){ + const currentBlock = runtime.getBlock(runtime.getRound()); + assert.equal(currentBlock.seed.length, 32); + expect(currentBlock.timestamp).to.be.a('bigint'); + }) + + it("Should produce a new block and move to next round", function(){ + const currentRound = runtime.getRound(); + const currentBlock = runtime.getBlock(currentRound); + //produce new block and move to next round + runtime.produceBlock(); + const newRound = runtime.getRound(); + const newBlock = runtime.getBlock(newRound); + assert.equal(currentRound + 1, newRound); + assert.notDeepEqual(currentBlock, newBlock); + assert.equal(currentBlock.timestamp + BlockFinalisationTime, newBlock.timestamp) + }) +}) From 27820e30444690a7fd94250a1bae5a79cc1d9069 Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Fri, 28 Oct 2022 01:45:32 +0200 Subject: [PATCH 10/24] add tests for runtime functions --- packages/runtime/test/src/runtime.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/test/src/runtime.ts b/packages/runtime/test/src/runtime.ts index d9ca7d990..1dbf577c3 100644 --- a/packages/runtime/test/src/runtime.ts +++ b/packages/runtime/test/src/runtime.ts @@ -1454,7 +1454,7 @@ describe.only("Funtions related to runtime chain", function(){ expect(currentBlock.timestamp).to.be.a('bigint'); }) - it("Should produce a new block and move to next round", function(){ + it.only("Should produce a new block and move to next round", function(){ const currentRound = runtime.getRound(); const currentBlock = runtime.getBlock(currentRound); //produce new block and move to next round From 1c33971803b16bb49468f3fe1121bc01cf1df0a8 Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Fri, 28 Oct 2022 01:46:14 +0200 Subject: [PATCH 11/24] add tests for runtime functions --- packages/runtime/test/src/runtime.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/test/src/runtime.ts b/packages/runtime/test/src/runtime.ts index 1dbf577c3..d9ca7d990 100644 --- a/packages/runtime/test/src/runtime.ts +++ b/packages/runtime/test/src/runtime.ts @@ -1454,7 +1454,7 @@ describe.only("Funtions related to runtime chain", function(){ expect(currentBlock.timestamp).to.be.a('bigint'); }) - it.only("Should produce a new block and move to next round", function(){ + it("Should produce a new block and move to next round", function(){ const currentRound = runtime.getRound(); const currentBlock = runtime.getBlock(currentRound); //produce new block and move to next round From c8c5c0bf6860599a225661331050e2812e0d265f Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Fri, 28 Oct 2022 01:47:57 +0200 Subject: [PATCH 12/24] add tests for runtime functions --- .husky/_/dissalowed_words.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.husky/_/dissalowed_words.sh b/.husky/_/dissalowed_words.sh index 00162ccfa..72328885d 100755 --- a/.husky/_/dissalowed_words.sh +++ b/.husky/_/dissalowed_words.sh @@ -15,3 +15,4 @@ do done done exit $status +exit 1 From b46f074e32d6f3b2ced30ed86dd481b418fa2880 Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Fri, 28 Oct 2022 01:48:39 +0200 Subject: [PATCH 13/24] add tests for runtime functions --- .husky/_/dissalowed_words.sh | 1 - packages/runtime/test/src/runtime.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.husky/_/dissalowed_words.sh b/.husky/_/dissalowed_words.sh index 72328885d..00162ccfa 100755 --- a/.husky/_/dissalowed_words.sh +++ b/.husky/_/dissalowed_words.sh @@ -15,4 +15,3 @@ do done done exit $status -exit 1 diff --git a/packages/runtime/test/src/runtime.ts b/packages/runtime/test/src/runtime.ts index d9ca7d990..1dbf577c3 100644 --- a/packages/runtime/test/src/runtime.ts +++ b/packages/runtime/test/src/runtime.ts @@ -1454,7 +1454,7 @@ describe.only("Funtions related to runtime chain", function(){ expect(currentBlock.timestamp).to.be.a('bigint'); }) - it("Should produce a new block and move to next round", function(){ + it.only("Should produce a new block and move to next round", function(){ const currentRound = runtime.getRound(); const currentBlock = runtime.getBlock(currentRound); //produce new block and move to next round From 03409df96a332e81d7c3b32f4975eada334fbeef Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Fri, 28 Oct 2022 02:09:24 +0200 Subject: [PATCH 14/24] test --- .husky/pre-commit | 1 + packages/runtime/test/src/runtime.ts | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index b15fa986d..091a73a76 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -3,3 +3,4 @@ . "$(dirname "$0")/_/dissalowed_words.sh" yarn run lint-staged + diff --git a/packages/runtime/test/src/runtime.ts b/packages/runtime/test/src/runtime.ts index 1dbf577c3..b7dfb90cb 100644 --- a/packages/runtime/test/src/runtime.ts +++ b/packages/runtime/test/src/runtime.ts @@ -1441,20 +1441,20 @@ describe("Helper functions", function () { }); }); }); -describe.only("Funtions related to runtime chain", function(){ +describe("Funtions related to runtime chain", function () { let runtime: Runtime; - this.beforeEach(function(){ + this.beforeEach(function () { runtime = new Runtime([]); - }) + }); - it("Should return current block", function(){ + it.only("Should return current block", function () { const currentBlock = runtime.getBlock(runtime.getRound()); assert.equal(currentBlock.seed.length, 32); - expect(currentBlock.timestamp).to.be.a('bigint'); - }) + expect(currentBlock.timestamp).to.be.a("bigint"); + }); - it.only("Should produce a new block and move to next round", function(){ + it("Should produce a new block and move to next round", function () { const currentRound = runtime.getRound(); const currentBlock = runtime.getBlock(currentRound); //produce new block and move to next round @@ -1463,6 +1463,6 @@ describe.only("Funtions related to runtime chain", function(){ const newBlock = runtime.getBlock(newRound); assert.equal(currentRound + 1, newRound); assert.notDeepEqual(currentBlock, newBlock); - assert.equal(currentBlock.timestamp + BlockFinalisationTime, newBlock.timestamp) - }) -}) + assert.equal(currentBlock.timestamp + BlockFinalisationTime, newBlock.timestamp); + }); +}); From fca66c61cd053cfaf10e4946bb597c11ecb8b351 Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Fri, 28 Oct 2022 02:10:45 +0200 Subject: [PATCH 15/24] test --- packages/runtime/test/src/runtime.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/test/src/runtime.ts b/packages/runtime/test/src/runtime.ts index b7dfb90cb..b22279a55 100644 --- a/packages/runtime/test/src/runtime.ts +++ b/packages/runtime/test/src/runtime.ts @@ -1448,7 +1448,7 @@ describe("Funtions related to runtime chain", function () { runtime = new Runtime([]); }); - it.only("Should return current block", function () { + it("Should return current block", function () { const currentBlock = runtime.getBlock(runtime.getRound()); assert.equal(currentBlock.seed.length, 32); expect(currentBlock.timestamp).to.be.a("bigint"); From 40a4c310a5568cf91a256c3adbdcb65bd8546c6c Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Fri, 28 Oct 2022 02:11:48 +0200 Subject: [PATCH 16/24] test --- .husky/pre-commit | 1 + 1 file changed, 1 insertion(+) diff --git a/.husky/pre-commit b/.husky/pre-commit index 091a73a76..803725380 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,5 @@ #!/bin/sh +echo "test" . "$(dirname "$0")/_/husky.sh" . "$(dirname "$0")/_/dissalowed_words.sh" From 63054b0987983c09658972fd159a2d50d0049868 Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Fri, 28 Oct 2022 02:15:05 +0200 Subject: [PATCH 17/24] test --- .husky/pre-commit | 1 - packages/runtime/test/src/runtime.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 803725380..091a73a76 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,4 @@ #!/bin/sh -echo "test" . "$(dirname "$0")/_/husky.sh" . "$(dirname "$0")/_/dissalowed_words.sh" diff --git a/packages/runtime/test/src/runtime.ts b/packages/runtime/test/src/runtime.ts index b22279a55..dcceb98e4 100644 --- a/packages/runtime/test/src/runtime.ts +++ b/packages/runtime/test/src/runtime.ts @@ -1441,7 +1441,7 @@ describe("Helper functions", function () { }); }); }); -describe("Funtions related to runtime chain", function () { +describe.only("Funtions related to runtime chain", function () { let runtime: Runtime; this.beforeEach(function () { From 5aa5ffae965b190a64b591cf5891deffa7277c27 Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Fri, 28 Oct 2022 02:18:29 +0200 Subject: [PATCH 18/24] remove .only from tests --- packages/runtime/test/src/runtime.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/test/src/runtime.ts b/packages/runtime/test/src/runtime.ts index dcceb98e4..b22279a55 100644 --- a/packages/runtime/test/src/runtime.ts +++ b/packages/runtime/test/src/runtime.ts @@ -1441,7 +1441,7 @@ describe("Helper functions", function () { }); }); }); -describe.only("Funtions related to runtime chain", function () { +describe("Funtions related to runtime chain", function () { let runtime: Runtime; this.beforeEach(function () { From 0d32529594f5713ccf679d68bc2c7d10b0920853 Mon Sep 17 00:00:00 2001 From: Stanislaw Czembor Date: Fri, 28 Oct 2022 04:03:58 +0200 Subject: [PATCH 19/24] add block opcode to parser --- packages/runtime/src/parser/parser.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/runtime/src/parser/parser.ts b/packages/runtime/src/parser/parser.ts index fdce32b91..00e93d141 100644 --- a/packages/runtime/src/parser/parser.ts +++ b/packages/runtime/src/parser/parser.ts @@ -156,6 +156,7 @@ import { Txna, Txnas, Uncover, + Block, } from "../interpreter/opcode-list"; import { LOGIC_SIG_MAX_COST, @@ -409,6 +410,7 @@ opCodeMap[7] = { sha3_256: Sha3_256, ed25519verify_bare: Ed25519verify_bare, json_ref: Json_ref, + block: Block, }; /** * TEALv8 @@ -486,6 +488,7 @@ const interpreterReqList = new Set([ "keccak256", "sha3_256", "ed25519verify", + "block", ]); const signatureModeOps = new Set(["arg", "args", "arg_0", "arg_1", "arg_2", "arg_3"]); From af3d55d0570f895418b7d9b25bd634f8e13d7909 Mon Sep 17 00:00:00 2001 From: sczembor <43810037+sczembor@users.noreply.github.com> Date: Wed, 2 Nov 2022 13:05:40 +0100 Subject: [PATCH 20/24] Apply suggestions from code review Co-authored-by: Ravindra Meena --- packages/runtime/src/interpreter/opcode-list.ts | 3 ++- packages/runtime/src/runtime.ts | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/runtime/src/interpreter/opcode-list.ts b/packages/runtime/src/interpreter/opcode-list.ts index c74fc2285..5b5cb3730 100644 --- a/packages/runtime/src/interpreter/opcode-list.ts +++ b/packages/runtime/src/interpreter/opcode-list.ts @@ -5312,6 +5312,7 @@ export class Block extends Op { this.line = line; this.interpreter = interpreter; } + execute(stack: TEALStack): number { this.assertMinStackLen(stack, 1, this.line); const round = Number(this.assertBigInt(stack.pop(), this.line)); @@ -5322,7 +5323,7 @@ export class Block extends Op { result = block.seed; } else { //"BlkTimestamp" - //seconds since epoch - rounds, assuming one round(block) = 2.5s truncated to 2s (BigInt) + //seconds since epoch - rounds, assuming one round(block) = 4.5s truncated to 4s (BigInt) result = block.timestamp; } stack.push(result); diff --git a/packages/runtime/src/runtime.ts b/packages/runtime/src/runtime.ts index 2d6574f31..785428b5c 100644 --- a/packages/runtime/src/runtime.ts +++ b/packages/runtime/src/runtime.ts @@ -1178,13 +1178,13 @@ export class Runtime { timestamp = BigInt(Math.round(new Date().getTime() / 1000)); } else { //add another block const lastBlock = this.store.blocks.get(this.round); - if (lastBlock !== undefined) { + if (lastBlock) { seed = new TextEncoder().encode(MD5(lastBlock.seed.toString()).toString()); timestamp = lastBlock.timestamp + BlockFinalisationTime; this.round += 1;// we move to new a new round } } - if (timestamp !== undefined && seed !== undefined) { + if (timestamp && seed) { this.store.blocks.set(this.round, { timestamp, seed }); } else { throw new RuntimeError(RUNTIME_ERRORS.GENERAL.PRODUCE_BLOCK); @@ -1197,7 +1197,7 @@ export class Runtime { */ getBlock(round: number): Block { const block = cloneDeep(this.store.blocks.get(round)); - if (block !== undefined) { + if (block) { return block; } throw new RuntimeError(RUNTIME_ERRORS.GENERAL.INVALID_BLOCK); From 7f6bc74eb3654d8da3de535fa30153da6085a1f4 Mon Sep 17 00:00:00 2001 From: sczembor <43810037+sczembor@users.noreply.github.com> Date: Wed, 2 Nov 2022 13:15:46 +0100 Subject: [PATCH 21/24] code review suggestions --- packages/runtime/src/interpreter/opcode-list.ts | 10 ++-------- .../runtime/test/src/interpreter/opcode-list.ts | 13 +++++++------ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/packages/runtime/src/interpreter/opcode-list.ts b/packages/runtime/src/interpreter/opcode-list.ts index 5b5cb3730..0bc95edee 100644 --- a/packages/runtime/src/interpreter/opcode-list.ts +++ b/packages/runtime/src/interpreter/opcode-list.ts @@ -5318,14 +5318,8 @@ export class Block extends Op { const round = Number(this.assertBigInt(stack.pop(), this.line)); this.interpreter.assertRoundIsAvailable(round); const block = this.interpreter.runtime.getBlock(round); - let result: StackElem; - if (this.field === blockFieldTypes.BlkSeed) { - result = block.seed; - } else { - //"BlkTimestamp" - //seconds since epoch - rounds, assuming one round(block) = 4.5s truncated to 4s (BigInt) - result = block.timestamp; - } + //"BlkTimestamp" = seconds since epoch, assuming one round(block) = 4.5s truncated to 4s (BigInt) + const result = (this.field === blockFieldTypes.BlkSeed) ? block.seed : block.timestamp stack.push(result); return this.computeCost(); } diff --git a/packages/runtime/test/src/interpreter/opcode-list.ts b/packages/runtime/test/src/interpreter/opcode-list.ts index f13d89a67..7502bddbd 100644 --- a/packages/runtime/test/src/interpreter/opcode-list.ts +++ b/packages/runtime/test/src/interpreter/opcode-list.ts @@ -175,6 +175,7 @@ import { MaxTEALVersion, MIN_UINT8, ZERO_ADDRESS, + blockFieldTypes, } from "../../../src/lib/constants"; import { bigEndianBytesToBigInt, @@ -7579,20 +7580,20 @@ describe("Teal Opcodes", function () { it("Should fail when accesing two behind FirstVaild because LastValid is 1000 after", function () { stack.push(BigInt(FIRST_VALID - 2n)); - const op = new Block(["BlkTimestamp"], 1, interpreter); + const op = new Block([blockFieldTypes.BlkTimestamp], 1, interpreter); assert.throws(() => op.execute(stack)); }); it("Should allow to acces two behind FirstValid if LastValid is 100 after", function () { interpreter.runtime.ctx.tx.lv = Number(FIRST_VALID) + 100; stack.push(BigInt(FIRST_VALID - 2n)); - const op = new Block(["BlkTimestamp"], 1, interpreter); + const op = new Block([blockFieldTypes.BlkTimestamp], 1, interpreter); assert.doesNotThrow(() => op.execute(stack)); }); it("Should return two different seeds for to different rounds", function () { interpreter.runtime.ctx.tx.lv = Number(FIRST_VALID) + 100; - const op = new Block(["BlkTimestamp"], 1, interpreter); + const op = new Block([blockFieldTypes.BlkSeed], 1, interpreter); //first round stack.push(FIRST_VALID - 1n); op.execute(stack); @@ -7608,13 +7609,13 @@ describe("Teal Opcodes", function () { interpreter.runtime.ctx.tx.lv = 100; interpreter.runtime.ctx.tx.fv = 5; stack.push(0n); - const op = new Block(["BlkTimestamp"], 1, interpreter); + const op = new Block([blockFieldTypes.BlkTimestamp], 1, interpreter); assert.throws(() => op.execute(stack)); }); it("Should return seed for a block that is within boundries and exist", function(){ stack.push(FIRST_VALID - 1n); - const op = new Block(["BlkSeed"], 1, interpreter); + const op = new Block([blockFieldTypes.BlkSeed], 1, interpreter); op.execute(stack); const result = stack.pop(); assert.equal((result as Buffer).length, 32); @@ -7622,7 +7623,7 @@ describe("Teal Opcodes", function () { it("Should return correct cost", function(){ stack.push(FIRST_VALID - 1n); - const op = new Block(["BlkSeed"], 1, interpreter); + const op = new Block([blockFieldTypes.BlkSeed], 1, interpreter); const cost = op.execute(stack); assert.equal(cost, 1); }); From c8b433b255c6470fe0ea929711f5d715c7e55c03 Mon Sep 17 00:00:00 2001 From: sczembor <43810037+sczembor@users.noreply.github.com> Date: Wed, 2 Nov 2022 20:58:46 +0100 Subject: [PATCH 22/24] declare strings and fixed integer values as const --- packages/runtime/src/interpreter/opcode-list.ts | 15 +++++++++------ packages/runtime/src/lib/constants.ts | 10 ++++++++++ packages/runtime/src/runtime.ts | 6 +++--- .../runtime/test/src/interpreter/opcode-list.ts | 17 +++++++++-------- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/packages/runtime/src/interpreter/opcode-list.ts b/packages/runtime/src/interpreter/opcode-list.ts index c47b935a3..2ee29aaa8 100644 --- a/packages/runtime/src/interpreter/opcode-list.ts +++ b/packages/runtime/src/interpreter/opcode-list.ts @@ -43,8 +43,11 @@ import { MAX_UINT128, MaxTEALVersion, OpGasCost, + proofLength, + publicKeyLength, TransactionTypeEnum, TxArrFields, + vrfVerifyFieldTypes, ZERO_ADDRESS, } from "../lib/constants"; import { addInnerTransaction, calculateInnerTxCredit, setInnerTxField } from "../lib/itxn"; @@ -5344,11 +5347,11 @@ export class VrfVerify extends Op { super(); this.line = line; switch (argument) { - case "VrfAlgorand": { + case vrfVerifyFieldTypes.VrfAlgorand: { this.vrfType = argument; break; } - case "VrfStandard": { + case vrfVerifyFieldTypes.VrfStandard: { this.vrfType = argument; break; } @@ -5359,7 +5362,7 @@ export class VrfVerify extends Op { } computeCost(): number { - return 5700; + return OpGasCost[7]["vrf_verify"]; } execute(stack: TEALStack): number { @@ -5368,13 +5371,13 @@ export class VrfVerify extends Op { const proof = this.assertBytes(stack.pop(), this.line); const publicKey = this.assertBytes(stack.pop(), this.line); - if (proof.length !== 80) { + if (proof.length !== proofLength) { throw new RuntimeError(RUNTIME_ERRORS.TEAL.INVALID_PROOF_LENGTH, {length: proof.length}); } - if (publicKey.length !== 32) { + if (publicKey.length !== publicKeyLength) { throw new RuntimeError(RUNTIME_ERRORS.TEAL.INVALID_PUB_KEY_LENGTH, {length: publicKey.length}); } - if (this.vrfType === "VrfAlgorand") { + if (this.vrfType === vrfVerifyFieldTypes.VrfAlgorand) { const hash = sha512(proof); stack.push(convertToBuffer(hash, EncodingType.HEX)); stack.push(1n); diff --git a/packages/runtime/src/lib/constants.ts b/packages/runtime/src/lib/constants.ts index 43e22d39f..0d2a70afe 100644 --- a/packages/runtime/src/lib/constants.ts +++ b/packages/runtime/src/lib/constants.ts @@ -40,6 +40,10 @@ export const MAX_INNER_TRANSACTIONS = 16; export const ALGORAND_MAX_LOGS_COUNT = 32; export const ALGORAND_MAX_LOGS_LENGTH = 1024; +export const publicKeyLength = 32; +export const proofLength = 80; +export const seedLength = 32; + export const MAX_ALGORAND_ACCOUNT_ASSETS = 1000; export const MAX_ALGORAND_ACCOUNT_CREATED_APPS = 10; @@ -478,6 +482,7 @@ OpGasCost[7] = { ...OpGasCost[6], sha3_256: 130, ed25519verify_bare: 1900, + vrf_verify : 5700, }; export const enum MathOp { @@ -525,6 +530,11 @@ export enum blockFieldTypes { BlkSeed = "BlkSeed", }; +export enum vrfVerifyFieldTypes { + VrfAlgorand = "VrfAlgorand", + VrfStandard = "VrfStandard", +}; + export enum TxFieldEnum { FirstValidTime = "FirstValidTime", TypeEnum = "TypeEnum", diff --git a/packages/runtime/src/runtime.ts b/packages/runtime/src/runtime.ts index 5bec2e48f..e561a36e1 100644 --- a/packages/runtime/src/runtime.ts +++ b/packages/runtime/src/runtime.ts @@ -23,9 +23,9 @@ import { BlockFinalisationTime, MAX_APP_PROGRAM_COST, MaxExtraAppProgramPages, + seedLength, TransactionTypeEnum, - ZERO_ADDRESS_STR -} from "./lib/constants"; + ZERO_ADDRESS_STR} from "./lib/constants"; import { convertToString } from "./lib/parsing"; import { LogicSigAccount } from "./logicsig"; import { mockSuggestedParams } from "./mock/tx"; @@ -1193,7 +1193,7 @@ export class Runtime { let timestamp: bigint | undefined; let seed: Uint8Array | undefined; if (this.store.blocks.size === 0) { //create genesis block - seed = nacl.randomBytes(32); + seed = nacl.randomBytes(seedLength); timestamp = BigInt(Math.round(new Date().getTime() / 1000)); } else { //add another block const lastBlock = this.store.blocks.get(this.round); diff --git a/packages/runtime/test/src/interpreter/opcode-list.ts b/packages/runtime/test/src/interpreter/opcode-list.ts index e606e5f92..91d241d7e 100644 --- a/packages/runtime/test/src/interpreter/opcode-list.ts +++ b/packages/runtime/test/src/interpreter/opcode-list.ts @@ -14,7 +14,6 @@ import { sha512_256 } from "js-sha512"; import cloneDeep from "lodash.clonedeep"; import { describe } from "mocha"; import nacl from "tweetnacl"; -import { isGeneratorFunction } from "util/types"; import { ExecutionMode } from "../../../build/types"; import { AccountStore } from "../../../src/account"; @@ -170,13 +169,15 @@ import { import { ALGORAND_ACCOUNT_MIN_BALANCE, ASSET_CREATION_FEE, + blockFieldTypes, DEFAULT_STACK_ELEM, MAX_UINT8, MAX_UINT64, MaxTEALVersion, MIN_UINT8, + vrfVerifyFieldTypes, ZERO_ADDRESS, - blockFieldTypes, + seedLength, } from "../../../src/lib/constants"; import { bigEndianBytesToBigInt, @@ -7619,7 +7620,7 @@ describe("Teal Opcodes", function () { const op = new Block([blockFieldTypes.BlkSeed], 1, interpreter); op.execute(stack); const result = stack.pop(); - assert.equal((result as Buffer).length, 32); + assert.equal((result as Buffer).length, seedLength); }); it("Should return correct cost", function(){ @@ -7651,7 +7652,7 @@ describe("Teal Opcodes", function () { }) it("Should return 1 and hash of proof for valid proof and verification key", function () { - const op = new VrfVerify(["VrfAlgorand"], 1); + const op = new VrfVerify([vrfVerifyFieldTypes.VrfAlgorand], 1); stack.push(publicKey); stack.push(proof); stack.push(message); @@ -7660,7 +7661,7 @@ describe("Teal Opcodes", function () { assert.deepEqual(expectedResult, stack.pop()); }); it("Should throw error if pubKey size not equal 32", function(){ - const op = new VrfVerify(["VrfAlgorand"], 1); + const op = new VrfVerify([vrfVerifyFieldTypes.VrfAlgorand], 1); const wrongSizePubKey = Buffer.from("b6b4699f87d56126c9117"); stack.push(wrongSizePubKey); stack.push(proof); @@ -7668,7 +7669,7 @@ describe("Teal Opcodes", function () { expectRuntimeError(() => op.execute(stack), RUNTIME_ERRORS.TEAL.INVALID_PUB_KEY_LENGTH); }) it("Should throw error if proof size not equal 80", function(){ - const op = new VrfVerify(["VrfAlgorand"], 1); + const op = new VrfVerify([vrfVerifyFieldTypes.VrfAlgorand], 1); const wrongSizeProof = Buffer.from("b6b4699f87d56126c9117"); stack.push(publicKey); stack.push(wrongSizeProof); @@ -7676,7 +7677,7 @@ describe("Teal Opcodes", function () { expectRuntimeError(() => op.execute(stack), RUNTIME_ERRORS.TEAL.INVALID_PROOF_LENGTH); }) it("Should return correct cost", function(){ - const op = new VrfVerify(["VrfAlgorand"], 1); + const op = new VrfVerify([vrfVerifyFieldTypes.VrfAlgorand], 1); stack.push(publicKey); stack.push(proof); stack.push(message); @@ -7684,7 +7685,7 @@ describe("Teal Opcodes", function () { assert.equal(cost, 5700); }) it("Should throw error when field = VrfStandard", function(){ - const op = new VrfVerify(["VrfStandard"], 1); + const op = new VrfVerify([vrfVerifyFieldTypes.VrfAlgorand], 1); stack.push(publicKey); stack.push(proof); stack.push(message); From 11bf244582800d0178df5e39eca873040bfd555d Mon Sep 17 00:00:00 2001 From: sczembor <43810037+sczembor@users.noreply.github.com> Date: Wed, 2 Nov 2022 21:07:19 +0100 Subject: [PATCH 23/24] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b45ebcbb..3b1d21d43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,8 @@ from `algosdk` and sends it to the network. - Added support for `vrf_verify` opcode to `Runtime`. IMPORTANT: the opcode assumes the proof is always valid thus it will always return 1. - Added program length check on app deploy on the basis of extra pages in `runtime`. - Added logic signature and arguments size check in `runtime`. +- Added support for `block` opcode to `Runtime`. +- Added blocks to `Runtime`. It simulates the block generation by using radnom bytes generator as the first seed. The following seeds are MD5 hash of the seed from the previous block. #### @algo-builder/web - Added support for logic signature to `executeTx` method of `Webmode` for AlgoSigner, MyAlgo Wallet and Wallet Connect. From fe8ff010f5cb9e68e90edcd728322e4e72fef31f Mon Sep 17 00:00:00 2001 From: sczembor <43810037+sczembor@users.noreply.github.com> Date: Wed, 2 Nov 2022 21:11:16 +0100 Subject: [PATCH 24/24] fix bug --- packages/runtime/test/src/interpreter/opcode-list.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/test/src/interpreter/opcode-list.ts b/packages/runtime/test/src/interpreter/opcode-list.ts index 91d241d7e..888cb4e56 100644 --- a/packages/runtime/test/src/interpreter/opcode-list.ts +++ b/packages/runtime/test/src/interpreter/opcode-list.ts @@ -7685,7 +7685,7 @@ describe("Teal Opcodes", function () { assert.equal(cost, 5700); }) it("Should throw error when field = VrfStandard", function(){ - const op = new VrfVerify([vrfVerifyFieldTypes.VrfAlgorand], 1); + const op = new VrfVerify([vrfVerifyFieldTypes.VrfStandard], 1); stack.push(publicKey); stack.push(proof); stack.push(message);