Skip to content

Commit

Permalink
Merge branch 'develop' into cli-watchGas-command
Browse files Browse the repository at this point in the history
  • Loading branch information
gtsonevv authored Oct 1, 2024
2 parents c36474d + 9623545 commit 772cc74
Show file tree
Hide file tree
Showing 111 changed files with 1,219 additions and 145 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ See more in the [Anatomy of a Contract](https://docs.near.org/build/smart-contra

## Documentation

- [Learn how to use](https://github.com/near/create-near-app/tree/master/templates/contracts/ts)
- [Learn by example with AgorApp](https://agorapp.dev/catalog/all?difficulty=&chains=near)
- [Learn by example with NEAR Docs](https://docs.near.org/build/smart-contracts/quickstart)
- Check our [detailed examples and tutorials](https://docs.near.org/tutorials/welcome)
Expand Down
151 changes: 151 additions & 0 deletions benchmark/__tests__/test-collections-performance.ava.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { Worker } from "near-workspaces";
import test from "ava";
import { logTotalGas, randomInt } from "./util.js";

const COLLECTION_SIZE = 20;

test.before(async (t) => {
// Init the worker and start a Sandbox server
const worker = await Worker.init();

// Prepare sandbox for tests, create accounts, deploy contracts, etx.
const root = worker.rootAccount;

// Deploy the test contracts.
const lookupMapContract = await root.devDeploy("build/lookup-map.wasm");
const lookupSetContract = await root.devDeploy("build/lookup-set.wasm");
const unorderedMapContract = await root.devDeploy("build/unordered-map.wasm");
const unorderedSetContract = await root.devDeploy("build/unordered-set.wasm");
const vectorContract = await root.devDeploy("build/vector.wasm");

// Test users
const ali = await root.createSubAccount("ali");

// Save state for test runs
t.context.worker = worker;
t.context.accounts = {
root,
lookupMapContract,
lookupSetContract,
unorderedMapContract,
unorderedSetContract,
vectorContract,
ali,
};
});

test.after.always(async (t) => {
await t.context.worker.tearDown().catch((error) => {
console.log("Failed to tear down the worker:", error);
});
});

test("JS lookup map contract operations", async (t) => {
const { ali, lookupMapContract } = t.context.accounts;

let rAdd;
for (let i = 0; i < COLLECTION_SIZE; i++) {
rAdd = await ali.callRaw(lookupMapContract, "addElement", { key: i, value: i });
}
t.is(rAdd.result.status.SuccessValue, "");
logTotalGas("Add element", rAdd, t);

const val = randomInt(COLLECTION_SIZE);
const rGet = await ali.callRaw(lookupMapContract, "getElement", { key: val });
t.is(JSON.parse(Buffer.from(rGet.result.status.SuccessValue, "base64")), val);
logTotalGas("Get element", rGet, t);

const rRem = await ali.callRaw(lookupMapContract, "removeElement", { key: randomInt(COLLECTION_SIZE) });
t.is(rRem.result.status.SuccessValue, "");
logTotalGas("Remove element", rRem, t);
});

test("JS lookup set contract operations", async (t) => {
const { ali, lookupSetContract } = t.context.accounts;

let rAdd;
for (let i = 0; i < COLLECTION_SIZE; i++) {
rAdd = await ali.callRaw(lookupSetContract, "addElement", { value: i });
}
t.is(rAdd.result.status.SuccessValue, "");
logTotalGas("Add element", rAdd, t);

const rGet = await ali.callRaw(lookupSetContract, "containsElement", { value: randomInt(COLLECTION_SIZE) });
t.is(JSON.parse(Buffer.from(rGet.result.status.SuccessValue, "base64")), true);
logTotalGas("Get element", rGet, t);

const rRem = await ali.callRaw(lookupSetContract, "removeElement", { value: randomInt(COLLECTION_SIZE) });
t.is(rRem.result.status.SuccessValue, "");
logTotalGas("Remove element", rRem, t);
});

test("JS unordered map contract operations", async (t) => {
const { ali, unorderedMapContract } = t.context.accounts;

let rAdd;
for (let i = 0; i < COLLECTION_SIZE; i++) {
rAdd = await ali.callRaw(unorderedMapContract, "addElement", { key: i, value: i });
}
t.is(rAdd.result.status.SuccessValue, "");
logTotalGas("Add element", rAdd, t);

const val = randomInt(COLLECTION_SIZE);
const rGet = await ali.callRaw(unorderedMapContract, "getElement", { key: val });
t.is(JSON.parse(Buffer.from(rGet.result.status.SuccessValue, "base64")), val);
logTotalGas("Get element", rGet, t);

const rIt = await ali.callRaw(unorderedMapContract, "iterate", {});
t.is(rIt.result.status.SuccessValue, "");
logTotalGas("Iterate collection", rIt, t);

const rRem = await ali.callRaw(unorderedMapContract, "removeElement", { key: randomInt(COLLECTION_SIZE) });
t.is(rRem.result.status.SuccessValue, "");
logTotalGas("Remove element", rRem, t);
});

test("JS unordered set contract operations", async (t) => {
const { ali, unorderedSetContract } = t.context.accounts;

let rAdd;
for (let i = 0; i < COLLECTION_SIZE; i++) {
rAdd = await ali.callRaw(unorderedSetContract, "addElement", { value: i });
}
t.is(rAdd.result.status.SuccessValue, "");
logTotalGas("Add element", rAdd, t);

const rGet = await ali.callRaw(unorderedSetContract, "containsElement", { value: randomInt(COLLECTION_SIZE) });
t.is(JSON.parse(Buffer.from(rGet.result.status.SuccessValue, "base64")), true);
logTotalGas ("Get element", rGet, t);

const rIt = await ali.callRaw(unorderedSetContract, "iterate", {});
t.is(rIt.result.status.SuccessValue, "");
logTotalGas("Iterate collection", rIt, t);

const rRem = await ali.callRaw(unorderedSetContract, "removeElement", { value: randomInt(COLLECTION_SIZE) });
t.is(rRem.result.status.SuccessValue, "");
logTotalGas("Remove element", rRem, t);
});

test("JS vector contract operations", async (t) => {
const { ali, vectorContract } = t.context.accounts;

let rAdd;
for (let i = 0; i < COLLECTION_SIZE; i++) {
rAdd = await ali.callRaw(vectorContract, "addElement", { value: i });
}
t.is(rAdd.result.status.SuccessValue, "");
logTotalGas("Add element", rAdd, t);

const val = randomInt(COLLECTION_SIZE);
const rGet = await ali.callRaw(vectorContract, "getElement", { index: val });
t.is(JSON.parse(Buffer.from(rGet.result.status.SuccessValue, "base64")), val);
logTotalGas("Get element", rGet, t);

const rIt = await ali.callRaw(vectorContract, "iterate", {});
t.is(rIt.result.status.SuccessValue, "");
logTotalGas("Iterate collection", rIt, t);

const rRem = await ali.callRaw(vectorContract, "removeElement", { index: randomInt(COLLECTION_SIZE) });
t.is(rRem.result.status.SuccessValue, "");
logTotalGas("Remove element", rRem, t);
});
17 changes: 17 additions & 0 deletions benchmark/__tests__/util.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Functions consumed by the benchmark contracts tests

export function formatGas(gas) {
if (gas < 10 ** 12) {
let tGas = gas / 10 ** 12;
Expand Down Expand Up @@ -49,3 +51,18 @@ export function logGasDetail(r, t) {
)
);
}

export function logTotalGas(prefix = '', r, t) {
t.log(
prefix + ' - Total gas used: ',
formatGas(
r.result.transaction_outcome.outcome.gas_burnt +
r.result.receipts_outcome[0].outcome.gas_burnt +
(r.result.receipts_outcome[1]?.outcome.gas_burnt || 0)
)
);
}

export function randomInt(max) {
return Math.floor(Math.random() * max);
}
8 changes: 7 additions & 1 deletion benchmark/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@
"build:highlevel-collection": "near-sdk-js build src/highlevel-collection.js build/highlevel-collection.wasm",
"build:expensive-calc": "near-sdk-js build src/expensive-calc.js build/expensive-calc.wasm",
"build:deploy-contract": "near-sdk-js build src/deploy-contract.js build/deploy-contract.wasm",
"build:lookup-map": "near-sdk-js build src/lookup-map.js build/lookup-map.wasm",
"build:lookup-set": "near-sdk-js build src/lookup-set.js build/lookup-set.wasm",
"build:unordered-map": "near-sdk-js build src/unordered-map.js build/unordered-map.wasm",
"build:unordered-set": "near-sdk-js build src/unordered-set.js build/unordered-set.wasm",
"build:vector": "near-sdk-js build src/vector.js build/vector.wasm",
"test": "ava",
"test:lowlevel-minimal": "ava __tests__/test-lowlevel-minimal.ava.js",
"test:highlevel-minimal": "ava __tests__/test-highlevel-minimal.ava.js",
"test:lowlevel-api": "ava __tests__/test-lowlevel-api.ava.js",
"test:highlevel-collection": "ava __tests__/test-highlevel-collection.ava.js",
"test:expensive-calc": "ava __tests__/test-expensive-calc.ava.js",
"test:deploy-contract": "ava __tests__/test-deploy-contract.ava.js"
"test:deploy-contract": "ava __tests__/test-deploy-contract.ava.js",
"test:collections": "ava __tests__/test-collections-performance.ava.js"
},
"author": "Near Inc <hello@nearprotocol.com>",
"license": "Apache-2.0",
Expand Down
5 changes: 5 additions & 0 deletions benchmark/src/deploy-contract.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { near } from "near-sdk-js";

/**
* Used for contract deployment. More information for that
* can be found in the README.md
* - Deploy and cross contract call
*/
export function deploy_contract() {
let promiseId = near.promiseBatchCreate("a.caller.test.near");
near.promiseBatchActionCreateAccount(promiseId);
Expand Down
5 changes: 5 additions & 0 deletions benchmark/src/expensive-calc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { NearBindgen, call, near } from "near-sdk-js";

/**
* ExpensiveCalc is connected to the expensive contract. More information for that
* can be found in the README.md
* - Computational expensive contract
*/
@NearBindgen({})
export class ExpensiveCalc {
@call({})
Expand Down
4 changes: 4 additions & 0 deletions benchmark/src/highlevel-collection.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { NearBindgen, call, UnorderedMap } from "near-sdk-js";

/**
* More information for that can be found in the README.md
* - Highlevel collection
*/
@NearBindgen({})
export class HighlevelCollection {
constructor() {
Expand Down
4 changes: 4 additions & 0 deletions benchmark/src/highlevel-minimal.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { NearBindgen, call } from "near-sdk-js";

/**
* More information for that can be found in the README.md
* - A highlevel minimal contract (using nearbindgen)
*/
@NearBindgen({})
export class HighlevelMinimal {
@call({})
Expand Down
23 changes: 23 additions & 0 deletions benchmark/src/lookup-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { NearBindgen, call, LookupMap, view } from "near-sdk-js";

@NearBindgen({})
export class LookupMapContract {
constructor() {
this.lookupMap = new LookupMap("LM");
}

@call({})
addElement({ key, value }) {
this.lookupMap.set(key, value);
}

@call({})
removeElement({ key }) {
this.lookupMap.remove(key);
}

@view({})
getElement({ key }) {
return this.lookupMap.get(key);
}
}
23 changes: 23 additions & 0 deletions benchmark/src/lookup-set.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { NearBindgen, call, LookupSet, view } from "near-sdk-js";

@NearBindgen({})
export class LookupSetContract {
constructor() {
this.lookupSet = new LookupSet("LS");
}

@call({})
addElement({ value }) {
this.lookupSet.set(value);
}

@call({})
removeElement({ value }) {
this.lookupSet.remove(value);
}

@view({})
containsElement({ value }) {
return this.lookupSet.contains(value);
}
}
8 changes: 8 additions & 0 deletions benchmark/src/lowlevel-api.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import { near } from "near-sdk-js";

/**
* Helper method for the low level api. More information for that can be found in the README.md
* - Low level API
*/
export function lowlevel_storage_write() {
let data = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
near.storageWriteRaw(data, data);
}

/**
* Helper method for the low level api. More information for that can be found in the README.md
* - Low level API
*/
export function lowlevel_storage_write_many() {
let data = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
near.storageWriteRaw(data, data);
Expand Down
4 changes: 4 additions & 0 deletions benchmark/src/lowlevel-minimal.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { near } from "near-sdk-js";

/**
* More information for that can be found in the README.md
* - A minimal contract
*/
export function empty() {}
31 changes: 31 additions & 0 deletions benchmark/src/unordered-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { NearBindgen, call, UnorderedMap, view } from "near-sdk-js";

@NearBindgen({})
export class UnorderedMapContract {
constructor() {
this.unorderedMap = new UnorderedMap("UM");
}

@call({})
addElement({ key, value }) {
this.unorderedMap.set(key, value);
}

@call({})
removeElement({ key }) {
this.unorderedMap.remove(key);
}

@view({})
getElement({ key }) {
return this.unorderedMap.get(key);
}

@view({})
iterate() {
const size = this.unorderedMap.length;
for (let i = 0; i < size; i++) {
this.unorderedMap.get(i);
}
}
}
31 changes: 31 additions & 0 deletions benchmark/src/unordered-set.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { NearBindgen, call, UnorderedSet, view } from "near-sdk-js";

@NearBindgen({})
export class UnorderedSetContract {
constructor() {
this.unorderedSet = new UnorderedSet("US");
}

@call({})
addElement({ value }) {
this.unorderedSet.set(value);
}

@call({})
removeElement({ value }) {
this.unorderedSet.remove(value);
}

@view({})
containsElement({ value }) {
return this.unorderedSet.contains(value);
}

@view({})
iterate() {
const size = this.unorderedSet.length;
for (let i = 0; i < size; i++) {
this.unorderedSet.contains(i);
}
}
}
Loading

0 comments on commit 772cc74

Please sign in to comment.