Skip to content

Commit

Permalink
Merge pull request #479 from multiversx/TOOL-248-add-workflow-to-run-…
Browse files Browse the repository at this point in the history
…integration-tests-with-localnet

Add workflow
  • Loading branch information
danielailie committed Sep 16, 2024
2 parents 04947e8 + 6d972bc commit 6dbbd06
Show file tree
Hide file tree
Showing 15 changed files with 267 additions and 93 deletions.
65 changes: 65 additions & 0 deletions .github/workflows/test-localnet.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: MultiversX Integration Tests

on:
push:
branches:
- main
pull_request:

jobs:
integration_tests:
runs-on: ubuntu-latest

steps:
# Step 1: Checkout the repository
- name: Checkout code
uses: actions/checkout@v3

# Step 2: Set up Python environment
- name: Set up Python 3.x
uses: actions/setup-python@v4
with:
python-version: '3.x'

# Step 3: Install pipx (to manage Python tools)
- name: Install pipx
run: |
python3 -m pip install --user pipx
python3 -m pipx ensurepath
# Add the pipx binary location to PATH
echo "$HOME/.local/bin" >> $GITHUB_PATH
shell: bash

# Step 4: Install mxpy (MultiversX Python SDK)
- name: Install mxpy (MultiversX SDK)
run: |
pipx install multiversx-sdk-cli --force
# Step 5: Set up MultiversX localnet using mxpy
- name: Set up MultiversX localnet
run: |
# Start the local testnet with mxpy
mkdir -p ~/localnet && cd ~/localnet
mxpy localnet setup
nohup mxpy localnet start > localnet.log 2>&1 & echo $! > localnet.pid
sleep 60 # Allow time for the testnet to fully start
# Step 6: Install Node.js and dependencies
- name: Set up Node.js environment
uses: actions/setup-node@v3
with:
node-version: '16.x'

- name: Install Node.js dependencies
run: npm install

# Step 7: Run integration tests
- name: Run integration tests
run: |
npm run tests-localnet
# Step 8: Stop the testnet using the stored PID
- name: Stop MultiversX local testnet
if: success() || failure()
run: |
kill $(cat localnet.pid) || echo "Testnet already stopped"
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@multiversx/sdk-core",
"version": "13.6.0",
"version": "13.6.1",
"description": "MultiversX SDK for JavaScript and TypeScript",
"author": "MultiversX",
"homepage": "https://multiversx.com",
Expand Down
13 changes: 13 additions & 0 deletions src/smartcontracts/codec/binary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import {
ArrayVec,
ManagedDecimalType,
ManagedDecimalValue,
ManagedDecimalSignedType,
ManagedDecimalSignedValue,
} from "../typesystem";
import { guardTrue } from "../../utils";
import { OptionValueBinaryCodec } from "./option";
Expand All @@ -28,6 +30,7 @@ import { EnumBinaryCodec } from "./enum";
import { TupleBinaryCodec } from "./tuple";
import { ArrayVecBinaryCodec } from "./arrayVec";
import { ManagedDecimalCodec } from "./managedDecimal";
import { ManagedDecimalSignedCodec } from "./managedDecimalSigned";

export class BinaryCodec {
readonly constraints: BinaryCodecConstraints;
Expand All @@ -39,6 +42,7 @@ export class BinaryCodec {
private readonly tupleCodec: TupleBinaryCodec;
private readonly enumCodec: EnumBinaryCodec;
private readonly managedDecimalCodec: ManagedDecimalCodec;
private readonly managedDecimalSignedCodec: ManagedDecimalSignedCodec;

constructor(constraints: BinaryCodecConstraints | null = null) {
this.constraints = constraints || new BinaryCodecConstraints();
Expand All @@ -50,6 +54,7 @@ export class BinaryCodec {
this.tupleCodec = new TupleBinaryCodec(this);
this.enumCodec = new EnumBinaryCodec(this);
this.managedDecimalCodec = new ManagedDecimalCodec(this);
this.managedDecimalSignedCodec = new ManagedDecimalSignedCodec(this);
}

decodeTopLevel<TResult extends TypedValue = TypedValue>(buffer: Buffer, type: Type): TResult {
Expand All @@ -64,6 +69,8 @@ export class BinaryCodec {
onTuple: () => this.tupleCodec.decodeTopLevel(buffer, <TupleType>type),
onEnum: () => this.enumCodec.decodeTopLevel(buffer, <EnumType>type),
onManagedDecimal: () => this.managedDecimalCodec.decodeTopLevel(buffer, <ManagedDecimalType>type),
onManagedDecimalSigned: () =>
this.managedDecimalSignedCodec.decodeTopLevel(buffer, <ManagedDecimalSignedType>type),
});

return <TResult>typedValue;
Expand All @@ -81,6 +88,8 @@ export class BinaryCodec {
onTuple: () => this.tupleCodec.decodeNested(buffer, <TupleType>type),
onEnum: () => this.enumCodec.decodeNested(buffer, <EnumType>type),
onManagedDecimal: () => this.managedDecimalCodec.decodeNested(buffer, <ManagedDecimalType>type),
onManagedDecimalSigned: () =>
this.managedDecimalSignedCodec.decodeNested(buffer, <ManagedDecimalSignedType>type),
});

return [<TResult>typedResult, decodedLength];
Expand All @@ -98,6 +107,8 @@ export class BinaryCodec {
onTuple: () => this.tupleCodec.encodeNested(<Tuple>typedValue),
onEnum: () => this.enumCodec.encodeNested(<EnumValue>typedValue),
onManagedDecimal: () => this.managedDecimalCodec.encodeNested(<ManagedDecimalValue>typedValue),
onManagedDecimalSigned: () =>
this.managedDecimalSignedCodec.encodeNested(<ManagedDecimalSignedValue>typedValue),
});
}

Expand All @@ -113,6 +124,8 @@ export class BinaryCodec {
onTuple: () => this.tupleCodec.encodeTopLevel(<Tuple>typedValue),
onEnum: () => this.enumCodec.encodeTopLevel(<EnumValue>typedValue),
onManagedDecimal: () => this.managedDecimalCodec.encodeTopLevel(<ManagedDecimalValue>typedValue),
onManagedDecimalSigned: () =>
this.managedDecimalSignedCodec.encodeTopLevel(<ManagedDecimalSignedValue>typedValue),
});
}
}
Expand Down
16 changes: 8 additions & 8 deletions src/smartcontracts/codec/managedDecimal.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import BigNumber from "bignumber.js";
import { BigUIntValue, ManagedDecimalType, ManagedDecimalValue, U32Value } from "../typesystem";
import { BigUIntType, BigUIntValue, ManagedDecimalType, ManagedDecimalValue, U32Value } from "../typesystem";
import { BinaryCodec } from "./binary";
import { bufferToBigInt } from "./utils";
import { SizeOfU32 } from "./constants";
Expand Down Expand Up @@ -27,25 +27,25 @@ export class ManagedDecimalCodec {
if (type.isVariable()) {
const bigUintSize = buffer.length - SizeOfU32;

const value = new BigNumber(buffer.slice(0, bigUintSize).toString("hex"), 16);
const [value] = this.binaryCodec.decodeNested(buffer.slice(0, bigUintSize), new BigUIntType());
const scale = buffer.readUInt32BE(bigUintSize);

return new ManagedDecimalValue(value, scale);
return new ManagedDecimalValue(value.valueOf().shiftedBy(-scale), scale);
}

const value = bufferToBigInt(buffer);
const metadata = type.getMetadata();
const scale = typeof metadata === "number" ? metadata : 0;
return new ManagedDecimalValue(value, scale);
const scale = metadata !== "usize" ? parseInt(metadata.toString()) : 0;
return new ManagedDecimalValue(value.shiftedBy(-scale), scale);
}

encodeNested(value: ManagedDecimalValue): Buffer {
let buffers: Buffer[] = [];
const rawValue = new BigUIntValue(value.valueOf().shiftedBy(value.getScale()));
if (value.isVariable()) {
buffers.push(Buffer.from(this.binaryCodec.encodeNested(new BigUIntValue(value.valueOf()))));
buffers.push(Buffer.from(this.binaryCodec.encodeNested(rawValue)));
buffers.push(Buffer.from(this.binaryCodec.encodeNested(new U32Value(value.getScale()))));
} else {
buffers.push(Buffer.from(this.binaryCodec.encodeTopLevel(new BigUIntValue(value.valueOf()))));
buffers.push(this.binaryCodec.encodeTopLevel(rawValue));
}
return Buffer.concat(buffers);
}
Expand Down
57 changes: 57 additions & 0 deletions src/smartcontracts/codec/managedDecimalSigned.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import BigNumber from "bignumber.js";
import { BigIntType, BigIntValue, ManagedDecimalSignedType, ManagedDecimalSignedValue, U32Value } from "../typesystem";
import { BinaryCodec } from "./binary";
import { bufferToBigInt } from "./utils";
import { SizeOfU32 } from "./constants";

export class ManagedDecimalSignedCodec {
private readonly binaryCodec: BinaryCodec;

constructor(binaryCodec: BinaryCodec) {
this.binaryCodec = binaryCodec;
}

decodeNested(buffer: Buffer, type: ManagedDecimalSignedType): [ManagedDecimalSignedValue, number] {
const length = buffer.readUInt32BE(0);
const payload = buffer.slice(0, length);

const result = this.decodeTopLevel(payload, type);
return [result, length];
}

decodeTopLevel(buffer: Buffer, type: ManagedDecimalSignedType): ManagedDecimalSignedValue {
if (buffer.length === 0) {
return new ManagedDecimalSignedValue(new BigNumber(0), 0);
}

if (type.isVariable()) {
const bigintSize = buffer.length - SizeOfU32;

const [value] = this.binaryCodec.decodeNested(buffer.slice(0, bigintSize), new BigIntType());
const scale = buffer.readUInt32BE(bigintSize);

return new ManagedDecimalSignedValue(value.valueOf().shiftedBy(-scale), scale);
}

const value = bufferToBigInt(buffer);
const metadata = type.getMetadata();
const scale = metadata !== "usize" ? parseInt(metadata.toString()) : 0;
return new ManagedDecimalSignedValue(value.shiftedBy(-scale), scale);
}

encodeNested(value: ManagedDecimalSignedValue): Buffer {
let buffers: Buffer[] = [];
const rawValue = new BigIntValue(value.valueOf().shiftedBy(value.getScale()));
if (value.isVariable()) {
buffers.push(Buffer.from(this.binaryCodec.encodeNested(rawValue)));
buffers.push(Buffer.from(this.binaryCodec.encodeNested(new U32Value(value.getScale()))));
} else {
buffers.push(Buffer.from(this.binaryCodec.encodeTopLevel(rawValue)));
}
return Buffer.concat(buffers);
}

encodeTopLevel(value: ManagedDecimalSignedValue): Buffer {
return this.encodeNested(value);
}
}
38 changes: 29 additions & 9 deletions src/smartcontracts/interaction.local.net.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ describe("test smart contract interactor", function () {
assert.isTrue(typedBundle.returnCode.equals(ReturnCode.Ok));
});

it("should interact with 'basic-features' (local testnet) using the SmartContractTransactionsFactory", async function () {
it("should interact with 'basic-features' (local testnet)", async function () {
this.timeout(140000);

let abiRegistry = await loadAbiRegistry("src/testdata/basic-features.abi.json");
Expand Down Expand Up @@ -226,7 +226,7 @@ describe("test smart contract interactor", function () {
.buildTransaction();

let additionInteraction = <Interaction>contract.methods
.managed_decimal_addition([new ManagedDecimalValue(2, 2), new ManagedDecimalValue(3, 2)])
.managed_decimal_addition([new ManagedDecimalValue("2.5", 2), new ManagedDecimalValue("2.7", 2)])
.withGasLimit(10000000)
.withChainID(network.ChainID)
.withSender(alice.address)
Expand All @@ -240,7 +240,7 @@ describe("test smart contract interactor", function () {

// log
let mdLnInteraction = <Interaction>contract.methods
.managed_decimal_ln([new ManagedDecimalValue(23000000000, 9)])
.managed_decimal_ln([new ManagedDecimalValue("23", 9)])
.withGasLimit(10000000)
.withChainID(network.ChainID)
.withSender(alice.address)
Expand All @@ -254,8 +254,8 @@ describe("test smart contract interactor", function () {

let additionVarInteraction = <Interaction>contract.methods
.managed_decimal_addition_var([
new ManagedDecimalValue(378298000000, 9, true),
new ManagedDecimalValue(378298000000, 9, true),
new ManagedDecimalValue("4", 2, true),
new ManagedDecimalValue("5", 2, true),
])
.withGasLimit(50000000)
.withChainID(network.ChainID)
Expand All @@ -268,33 +268,53 @@ describe("test smart contract interactor", function () {
.useThenIncrementNonceOf(alice.account)
.buildTransaction();

let lnVarInteraction = <Interaction>contract.methods
.managed_decimal_ln_var([new ManagedDecimalValue("23", 9, true)])
.withGasLimit(50000000)
.withChainID(network.ChainID)
.withSender(alice.address)
.withValue(0);

// managed_decimal_ln_var()
let lnVarTransaction = lnVarInteraction
.withSender(alice.address)
.useThenIncrementNonceOf(alice.account)
.buildTransaction();

// returnEgld()
await signTransaction({ transaction: returnEgldTransaction, wallet: alice });
let { bundle: bundleEgld } = await controller.execute(returnEgldInteraction, returnEgldTransaction);
assert.isTrue(bundleEgld.returnCode.equals(ReturnCode.Ok));
assert.lengthOf(bundleEgld.values, 1);
assert.deepEqual(bundleEgld.values[0], new ManagedDecimalValue(1, 18));
assert.deepEqual(bundleEgld.values[0], new ManagedDecimalValue("0.000000000000000001", 18));

// addition with const decimals()
await signTransaction({ transaction: additionTransaction, wallet: alice });
let { bundle: bundleAdditionConst } = await controller.execute(additionInteraction, additionTransaction);
assert.isTrue(bundleAdditionConst.returnCode.equals(ReturnCode.Ok));
assert.lengthOf(bundleAdditionConst.values, 1);
assert.deepEqual(bundleAdditionConst.values[0], new ManagedDecimalValue(5, 2));
assert.deepEqual(bundleAdditionConst.values[0], new ManagedDecimalValue("5.2", 2));

// log
await signTransaction({ transaction: mdLnTransaction, wallet: alice });
let { bundle: bundleMDLn } = await controller.execute(mdLnInteraction, mdLnTransaction);
assert.isTrue(bundleMDLn.returnCode.equals(ReturnCode.Ok));
assert.lengthOf(bundleMDLn.values, 1);
assert.deepEqual(bundleMDLn.values[0], new ManagedDecimalSignedValue(3135553845, 9));
assert.deepEqual(bundleMDLn.values[0], new ManagedDecimalSignedValue("3.135553845", 9));

// addition with var decimals
await signTransaction({ transaction: additionVarTransaction, wallet: alice });
let { bundle: bundleAddition } = await controller.execute(additionVarInteraction, additionVarTransaction);
assert.isTrue(bundleAddition.returnCode.equals(ReturnCode.Ok));
assert.lengthOf(bundleAddition.values, 1);
assert.deepEqual(bundleAddition.values[0], new ManagedDecimalValue(new BigNumber(6254154138880), 9));
assert.deepEqual(bundleAddition.values[0], new ManagedDecimalValue("9", 2));

// log
await signTransaction({ transaction: lnVarTransaction, wallet: alice });
let { bundle: bundleLnVar } = await controller.execute(lnVarInteraction, lnVarTransaction);
assert.isTrue(bundleLnVar.returnCode.equals(ReturnCode.Ok));
assert.lengthOf(bundleLnVar.values, 1);
assert.deepEqual(bundleLnVar.values[0], new ManagedDecimalSignedValue("3.135553845", 9));
});

it("should interact with 'counter' (local testnet)", async function () {
Expand Down
1 change: 1 addition & 0 deletions src/smartcontracts/typesystem/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ export * from "./typeMapper";
export * from "./types";
export * from "./variadic";
export * from "./managedDecimal";
export * from "./managedDecimalSigned";
Loading

0 comments on commit 6dbbd06

Please sign in to comment.