Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implementation for block opcode #816

Merged
merged 28 commits into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
475673f
draft implementation for block opcode
sczembor Oct 19, 2022
cf2889f
better way to mock the seed and timestamp
sczembor Oct 19, 2022
8d4e7c8
changing the constans
sczembor Oct 20, 2022
95f0813
Merge branch 'develop' into block_opcode
sczembor Oct 25, 2022
34dcac2
add blocks to runtime
sczembor Oct 26, 2022
1cdba96
Add block to runtime; test scenario; block opcode
sczembor Oct 27, 2022
1efe617
Merge branch 'develop' into block_opcode
sczembor Oct 27, 2022
3fca297
change defult value of round to 2000
sczembor Oct 27, 2022
3d94a0f
Merge branch 'block_opcode' of https://github.com/scale-it/algo-build…
sczembor Oct 27, 2022
dc20456
change finalisation time
sczembor Oct 27, 2022
1c4bb9c
add enum; add proper error
sczembor Oct 27, 2022
4537e87
add tests for runtime functions
sczembor Oct 27, 2022
27820e3
add tests for runtime functions
sczembor Oct 27, 2022
1c33971
add tests for runtime functions
sczembor Oct 27, 2022
c8c5c0b
add tests for runtime functions
sczembor Oct 27, 2022
b46f074
add tests for runtime functions
sczembor Oct 27, 2022
03409df
test
sczembor Oct 28, 2022
fca66c6
test
sczembor Oct 28, 2022
40a4c31
test
sczembor Oct 28, 2022
63054b0
test
sczembor Oct 28, 2022
5aa5ffa
remove .only from tests
sczembor Oct 28, 2022
0d32529
add block opcode to parser
sczembor Oct 28, 2022
af3d55d
Apply suggestions from code review
sczembor Nov 2, 2022
7f6bc74
code review suggestions
sczembor Nov 2, 2022
b40c073
Merge branch 'develop' into block_opcode
sczembor Nov 2, 2022
c8b433b
declare strings and fixed integer values as const
sczembor Nov 2, 2022
11bf244
update changelog
sczembor Nov 2, 2022
fe8ff01
fix bug
sczembor Nov 2, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
. "$(dirname "$0")/_/dissalowed_words.sh"

yarn run lint-staged

2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions packages/runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.22.0",
"chalk": "^4.1.2",
"crypto-js": "^4.1.1",
"debug": "^4.3.4",
"elliptic": "^6.5.4",
"hi-base32": "^0.5.1",
Expand Down
20 changes: 19 additions & 1 deletion packages/runtime/src/errors/errors-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ maximun uint128`,
},
UNKNOWN_VRF_TYPE: {
number: 1070,
message: "Unknown field",
message: "Unknown vrf_verify field",
title: "Unknown field",
description: "Unknow field for vrf_verify opcode",
},
Expand All @@ -487,6 +487,12 @@ maximun uint128`,
description:
"Allowed extra pages range is from 0 to %maxExtraAppProgramPages% but got %extraPages% extra pages",
},
UNKNOWN_BLOCK_FIELD: {
number: 1072,
message: "Unknown block opcode field",
title: "Unknown field",
description: "Block opcode support only BlkTimestamp and BlkSeed field, got: %field",
}
};

const runtimeGeneralErrors = {
Expand Down Expand Up @@ -627,6 +633,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 = {
Expand Down
27 changes: 26 additions & 1 deletion packages/runtime/src/interpreter/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
DEFAULT_STACK_ELEM,
LOGIC_SIG_MAX_COST,
MaxTEALVersion,
MaxTxnLife,
MinVersionSupportC2CCall,
TransactionTypeEnum,
} from "../lib/constants";
Expand Down Expand Up @@ -170,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) ||
Expand Down Expand Up @@ -595,4 +596,28 @@ export class Interpreter {
}
return result;
}

/**
* 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;
}
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("round is not available");
//todo: add better error
// throw error ("round %d is not available. It's outside [%d-%d]", r, firstAvail, lastAvail)
}
}
}
59 changes: 53 additions & 6 deletions packages/runtime/src/interpreter/opcode-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
ALGORAND_MAX_LOGS_LENGTH,
AppParamDefined,
AssetParamMap,
blockFieldTypes,
GlobalFields,
ITxArrFields,
json_refTypes,
Expand All @@ -42,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";
Expand Down Expand Up @@ -5209,6 +5213,7 @@ export class Json_ref extends Op {
return this.computeCost();
}
}
//TODO:add description
export class Bn254Add extends Op {
readonly line: number;
/**
Expand All @@ -5232,6 +5237,7 @@ export class Bn254Add extends Op {
return this.computeCost();
}
}
//TODO:add description
export class Bn254ScalarMul extends Op {
readonly line: number;
/**
Expand All @@ -5255,6 +5261,7 @@ export class Bn254ScalarMul extends Op {
return this.computeCost();
}
}
//TODO:add description
export class Bn254Pairing extends Op {
readonly line: number;
/**
Expand All @@ -5279,6 +5286,46 @@ export class Bn254Pairing extends Op {
return this.computeCost();
}
}

/**
* 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;
/**
* @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();
assertLen(args.length, 1, line);
const argument = args[0];
if (argument === blockFieldTypes.BlkSeed|| argument === blockFieldTypes.BlkTimestamp) {
this.field = argument;
} else {
throw new RuntimeError(RUNTIME_ERRORS.TEAL.UNKNOWN_BLOCK_FIELD, {field: argument});
}
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));
this.interpreter.assertRoundIsAvailable(round);
const block = this.interpreter.runtime.getBlock(round);
//"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();
}
};

/**
* Opcode: 0xd0 {uint8 parameters index}
* Stack: ..., A: []byte, B: []byte, C: []byte → ..., X: []byte, Y: uint64
Expand All @@ -5300,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;
}
Expand All @@ -5315,7 +5362,7 @@ export class VrfVerify extends Op {
}

computeCost(): number {
return 5700;
return OpGasCost[7]["vrf_verify"];
}

execute(stack: TEALStack): number {
Expand All @@ -5324,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);
Expand Down
3 changes: 2 additions & 1 deletion packages/runtime/src/interpreter/opcode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down
18 changes: 18 additions & 0 deletions packages/runtime/src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -56,6 +60,9 @@ 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;
export const BlockFinalisationTime = 4n; // block finalisation time in seconds truncated down

export const ZERO_ADDRESS = new Uint8Array(32);
export const ZERO_ADDRESS_STR = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ";
const zeroUint64 = 0n;
Expand Down Expand Up @@ -475,6 +482,7 @@ OpGasCost[7] = {
...OpGasCost[6],
sha3_256: 130,
ed25519verify_bare: 1900,
vrf_verify : 5700,
};

export const enum MathOp {
Expand Down Expand Up @@ -517,6 +525,16 @@ export const json_refTypes = {
JSONObject: "JSONObject",
};

export enum blockFieldTypes {
BlkTimestamp = "BlkTimestamp",
BlkSeed = "BlkSeed",
};

export enum vrfVerifyFieldTypes {
VrfAlgorand = "VrfAlgorand",
VrfStandard = "VrfStandard",
};

export enum TxFieldEnum {
FirstValidTime = "FirstValidTime",
TypeEnum = "TypeEnum",
Expand Down
3 changes: 3 additions & 0 deletions packages/runtime/src/parser/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ import {
Txna,
Txnas,
Uncover,
Block,
VrfVerify,
} from "../interpreter/opcode-list";
import {
Expand Down Expand Up @@ -410,6 +411,7 @@ opCodeMap[7] = {
sha3_256: Sha3_256,
ed25519verify_bare: Ed25519verify_bare,
json_ref: Json_ref,
block: Block,
vrf_verify: VrfVerify,
};
/**
Expand Down Expand Up @@ -488,6 +490,7 @@ const interpreterReqList = new Set([
"keccak256",
"sha3_256",
"ed25519verify",
"block",
]);

const signatureModeOps = new Set(["arg", "args", "arg_0", "arg_1", "arg_2", "arg_3"]);
Expand Down
Loading