diff --git a/.github/workflows/contract-tests.yml b/.github/workflows/contract-tests.yml index 2e74e408b3..827d735419 100644 --- a/.github/workflows/contract-tests.yml +++ b/.github/workflows/contract-tests.yml @@ -49,11 +49,20 @@ jobs: sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get update sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get install -y --no-install-recommends -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" build-essential clang curl libssl-dev llvm libudev-dev protobuf-compiler nodejs pkg-config + - name: Build node-subtensor and Ink contracts + run: | + cd ${{ github.workspace }} + rustup component add rust-src + cargo install cargo-contract + cargo build --release -p node-subtensor --features fast-runtime + cd contract-tests/bittensor + cargo contract build --release + - name: Run tests uses: nick-fields/retry@v3 with: timeout_minutes: 90 - max_attempts: 3 + max_attempts: 5 retry_wait_seconds: 60 command: | cd ${{ github.workspace }} diff --git a/contract-tests/run-ci.sh b/contract-tests/run-ci.sh index 0ea0e72297..935f39ff23 100755 --- a/contract-tests/run-ci.sh +++ b/contract-tests/run-ci.sh @@ -2,20 +2,10 @@ echo "start run-ci.sh" -cd contract-tests - -cd bittensor - -rustup component add rust-src -cargo install cargo-contract -cargo contract build --release - -cd ../.. - -scripts/localnet.sh &>/dev/null & +target/release/node-subtensor --dev --tmp --one &>/dev/null & i=1 -while [ $i -le 2000 ]; do +while [ $i -le 60 ]; do if nc -z localhost 9944; then echo "node subtensor is running after $i seconds" break @@ -25,11 +15,11 @@ while [ $i -le 2000 ]; do done # port not available exit with error -if [ "$i" -eq 2000 ]; then +if [ "$i" -eq 60 ]; then exit 1 fi -sleep 10 +sleep 2 if ! nc -z localhost 9944; then echo "node subtensor exit, port not available" @@ -43,7 +33,7 @@ npm i -g polkadot-api bash get-metadata.sh -sleep 5 +sleep 2 yarn install --frozen-lockfile diff --git a/contract-tests/src/substrate.ts b/contract-tests/src/substrate.ts index c7c9efe3d9..3e4d9698fb 100644 --- a/contract-tests/src/substrate.ts +++ b/contract-tests/src/substrate.ts @@ -180,7 +180,6 @@ export async function getTransactionWatchPromise(tx: Transaction<{}, string, str // TODO investigate why finalized not for each extrinsic if (value.type === "finalized") { - console.log("Transaction is finalized in block:", value.txHash); subscription.unsubscribe(); clearTimeout(timeoutId); if (!value.ok) { diff --git a/contract-tests/src/subtensor.ts b/contract-tests/src/subtensor.ts index 12d652a9a3..29a17a79fb 100644 --- a/contract-tests/src/subtensor.ts +++ b/contract-tests/src/subtensor.ts @@ -1,11 +1,10 @@ import * as assert from "assert"; import { devnet, MultiAddress } from '@polkadot-api/descriptors'; -import { TypedApi, TxCallData, Binary, Enum } from 'polkadot-api'; +import { TypedApi, TxCallData, Binary, Enum, getTypedCodecs } from 'polkadot-api'; import { KeyPair } from "@polkadot-labs/hdkd-helpers" import { getAliceSigner, waitForTransactionCompletion, getSignerFromKeypair, waitForTransactionWithRetry } from './substrate' import { convertH160ToSS58, convertPublicKeyToSs58, ethAddressToH160 } from './address-utils' import { tao } from './balance-math' -import internal from "stream"; // create a new subnet and return netuid export async function addNewSubnetwork(api: TypedApi, hotkey: KeyPair, coldkey: KeyPair) { @@ -26,6 +25,8 @@ export async function addNewSubnetwork(api: TypedApi, hotkey: Key const newTotalNetworks = await api.query.SubtensorModule.TotalNetworks.getValue() // could create multiple subnetworks during retry, just return the first created one assert.ok(newTotalNetworks > totalNetworks) + // reset network last lock to 0 for tests + await resetNetworkLastLock(api) return totalNetworks } @@ -398,4 +399,23 @@ export async function sendWasmContractExtrinsic(api: TypedApi, co storage_deposit_limit: BigInt(1000000000) }) await waitForTransactionWithRetry(api, tx, signer) -} \ No newline at end of file +} + +// Reset network last lock to 0 for tests, then the cose for network registration will be the default minimum +// We can make the const cost for each network registration for tests. avoid the cost spike +export async function resetNetworkLastLock(api: TypedApi) { + const alice = getAliceSigner() + const key = await api.query.SubtensorModule.NetworkLastLockCost.getKey() + + // Get the codec for NetworkLastLockCost value (TaoCurrency/u128) + const codec = await getTypedCodecs(devnet) + const valueCodec = codec.query.SubtensorModule.NetworkLastLockCost.value + + // Encode the value 0 as SCALE-encoded bytes + const encodedValue = valueCodec.enc(BigInt(0)) + + const changes: [Binary, Binary][] = [[Binary.fromHex(key.toString()), Binary.fromBytes(encodedValue)]]; + const internalCall = api.tx.System.set_storage({ items: changes }) + const tx = api.tx.Sudo.sudo({ call: internalCall.decodedCall }) + await waitForTransactionWithRetry(api, tx, alice) +} \ No newline at end of file diff --git a/contract-tests/test/alphaPool.test.ts b/contract-tests/test/alphaPool.test.ts index 361e1213bb..d6aefc4bcc 100644 --- a/contract-tests/test/alphaPool.test.ts +++ b/contract-tests/test/alphaPool.test.ts @@ -14,7 +14,7 @@ import { ethers } from "ethers" import { tao } from "../src/balance-math"; import { ISTAKING_V2_ADDRESS, IStakingV2ABI } from "../src/contracts/staking"; // import { KeyPair } from "@polkadot-labs/hdkd-helpers"; -describe("bridge token contract deployment", () => { +describe("Alpha Pool Test", () => { // init eth part const wallet = generateRandomEthersWallet(); let publicClient: PublicClient; diff --git a/contract-tests/test/leasing.precompile.test.ts b/contract-tests/test/leasing.precompile.test.ts index 7ea45c0509..895a7ef84a 100644 --- a/contract-tests/test/leasing.precompile.test.ts +++ b/contract-tests/test/leasing.precompile.test.ts @@ -7,7 +7,7 @@ import { ethers } from "ethers"; import { TypedApi } from "polkadot-api"; import { devnet } from "@polkadot-api/descriptors"; import { getAliceSigner, getBobSigner, getDevnetApi, waitForFinalizedBlock } from "../src/substrate"; -import { forceSetBalanceToEthAddress } from "../src/subtensor"; +import { forceSetBalanceToEthAddress, resetNetworkLastLock } from "../src/subtensor"; import { decodeAddress } from "@polkadot/util-crypto"; import { u8aToHex } from "@polkadot/util"; import { ILEASING_ADDRESS, ILeasingABI } from "../src/contracts/leasing"; @@ -24,6 +24,8 @@ describe("Test Leasing precompile", () => { let leaseContract: ethers.Contract; let crowdloanContract: ethers.Contract; let neuronContract: ethers.Contract; + const crowdloanDeposit = BigInt(100_000_000_000); + let crowdloanCap: bigint; const alice = getAliceSigner(); const bob = getBobSigner(); @@ -40,12 +42,19 @@ describe("Test Leasing precompile", () => { await forceSetBalanceToEthAddress(api, wallet1.address); await forceSetBalanceToEthAddress(api, wallet2.address); + + await resetNetworkLastLock(api); + const minLockCost = await api.query.SubtensorModule.NetworkMinLockCost.getValue(); + // guarantee that the crowdloan cap is larger than the deposit + if (minLockCost > crowdloanDeposit) { + crowdloanCap = minLockCost * BigInt(2); + } else { + crowdloanCap = crowdloanDeposit * BigInt(2); + } }); it("gets an existing lease created on substrate side, its subnet id and its contributor shares", async () => { const nextCrowdloanId = await api.query.Crowdloan.NextCrowdloanId.getValue(); - const crowdloanDeposit = BigInt(100_000_000_000); // 100 TAO - const crowdloanCap = await api.query.SubtensorModule.NetworkLastLockCost.getValue() * BigInt(2); const crowdloanEnd = await api.query.System.Number.getValue() + 100; const leaseEmissionsShare = 15; const leaseEnd = await api.query.System.Number.getValue() + 300; @@ -67,8 +76,8 @@ describe("Test Leasing precompile", () => { amount: crowdloanCap - crowdloanDeposit, }).signAndSubmit(bob); - await waitForFinalizedBlock(api, crowdloanEnd); + await waitForFinalizedBlock(api, crowdloanEnd); const nextLeaseId = await api.query.SubtensorModule.NextSubnetLeaseId.getValue(); await api.tx.Crowdloan.finalize({ crowdloan_id: nextCrowdloanId }).signAndSubmit(alice); @@ -98,9 +107,7 @@ describe("Test Leasing precompile", () => { it("registers a new leased network through a crowdloan and retrieves the lease", async () => { const nextCrowdloanId = await api.query.Crowdloan.NextCrowdloanId.getValue(); - const crowdloanDeposit = BigInt(100_000_000_000); // 100 TAO const crowdloanMinContribution = BigInt(1_000_000_000); // 1 TAO - const crowdloanCap = await api.query.SubtensorModule.NetworkLastLockCost.getValue() * BigInt(2); const crowdloanEnd = await api.query.System.Number.getValue() + 100; const leasingEmissionsShare = 15; const leasingEndBlock = await api.query.System.Number.getValue() + 300; @@ -159,9 +166,7 @@ describe("Test Leasing precompile", () => { await tx.wait(); const nextCrowdloanId = await api.query.Crowdloan.NextCrowdloanId.getValue(); - const crowdloanDeposit = BigInt(100_000_000_000); // 100 TAO const crowdloanMinContribution = BigInt(1_000_000_000); // 1 TAO - const crowdloanCap = await api.query.SubtensorModule.NetworkLastLockCost.getValue() * BigInt(2); const crowdloanEnd = await api.query.System.Number.getValue() + 100; const leasingEmissionsShare = 15; const leasingEndBlock = await api.query.System.Number.getValue() + 200; diff --git a/contract-tests/test/staking.precompile.full-limit.test.ts b/contract-tests/test/staking.precompile.full-limit.test.ts index 156fd38f25..24c5507a88 100644 --- a/contract-tests/test/staking.precompile.full-limit.test.ts +++ b/contract-tests/test/staking.precompile.full-limit.test.ts @@ -62,7 +62,7 @@ describe("Test staking precompile add remove limit methods", () => { IStakingV2ABI, wallet1, ); - + await new Promise(resolve => setTimeout(resolve, 1000)); const tx = await contract.addStakeLimit( hotkey.publicKey, tao(2000), @@ -131,7 +131,7 @@ describe("Test staking precompile add remove limit methods", () => { IStakingV2ABI, wallet2, ); - + await new Promise(resolve => setTimeout(resolve, 1000)); const tx = await contract.addStakeLimit( hotkey.publicKey, tao(2000), @@ -165,7 +165,7 @@ describe("Test staking precompile add remove limit methods", () => { IStakingV2ABI, wallet2, ); - + await new Promise(resolve => setTimeout(resolve, 1000)); const tx = await contract.removeStakeFull( hotkey.publicKey, netuid, diff --git a/contract-tests/test/staking.precompile.wrap.test.ts b/contract-tests/test/staking.precompile.wrap.test.ts index e4d666adf1..07eb7e6e6d 100644 --- a/contract-tests/test/staking.precompile.wrap.test.ts +++ b/contract-tests/test/staking.precompile.wrap.test.ts @@ -20,6 +20,7 @@ import { ethers } from "ethers"; import { generateRandomEthersWallet } from "../src/utils"; import { abi, bytecode } from "../src/contracts/stakeWrap"; +import { setMaxIdleHTTPParsers } from "http"; describe("Test staking precompile add from deployed contract", () => { const hotkey = getRandomSubstrateKeypair(); @@ -62,12 +63,15 @@ describe("Test staking precompile add from deployed contract", () => { const txResponse = await wallet1.sendTransaction(ethTransfer) await txResponse.wait(); + console.log("stakeWrap contract deployed, target: ", contract.target.toString()); + const deployedContract = new ethers.Contract( contract.target.toString(), abi, wallet1, ); + await new Promise(resolve => setTimeout(resolve, 1000)); const tx = await deployedContract.stake( hotkey.publicKey, netuid, @@ -75,6 +79,8 @@ describe("Test staking precompile add from deployed contract", () => { ); await tx.wait(); + await new Promise(resolve => setTimeout(resolve, 1000)); + const tx2 = await deployedContract.removeStake( hotkey.publicKey, netuid, diff --git a/contract-tests/test/subnet.precompile.hyperparameter.test.ts b/contract-tests/test/subnet.precompile.hyperparameter.test.ts index 87968b6e9f..40b0a77987 100644 --- a/contract-tests/test/subnet.precompile.hyperparameter.test.ts +++ b/contract-tests/test/subnet.precompile.hyperparameter.test.ts @@ -29,6 +29,10 @@ describe("Test the Subnet precompile contract", () => { await disableAdminFreezeWindowAndOwnerHyperparamRateLimit(api) }) + beforeEach(async () => { + await new Promise(resolve => setTimeout(resolve, 500)) + }) + it("Can register network without identity info", async () => { const totalNetwork = await api.query.SubtensorModule.TotalNetworks.getValue() diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 52746675f9..48e49b76c9 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -241,7 +241,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 365, + spec_version: 366, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,