mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-23 17:28:23 +00:00
test: Port Moonbeam Moonwall E2E test suites to DataHaven (#436)
## Summary - Port 16 Moonbeam Moonwall E2E test suites to DataHaven, covering proxy, multisig, sudo, txpool, receipts, precompiles, polkadot-js API, and node RPC - Adapt all tests for DataHaven runtime differences: 2 inherents (timestamp + randomness) instead of Moonbeam's 4, different event ordering/counts from fee/treasury handling, no PoV constraints - Use resilient event-based lookups (`.find()`/`.some()`) instead of hardcoded array indices throughout - Add supporting Solidity contracts: `FailingConstructor`, `StorageLoop` ## New test suites | Suite | Category | Tests | |-------|----------|-------| | `test-proxy-balance` | common/proxy | Proxy with Balances type | | `test-proxy` | stagenet/proxy | Add/remove proxy, delayed & announced proxy (7 tests) | | `test-multisigs` | stagenet/multisig | Creation, approval, execution, cancellation | | `test-sudo` | stagenet/sudo | Dispatch, sudoAs, set/remove key | | `test-polkadot-api` | stagenet/polkadot-js | Genesis, headers, transfers, extrinsics, events | | `test-polkadot-chain-info` | stagenet/polkadot-js | Chain name/type queries | | `test-node-rpc-peer` | stagenet/node-rpc | `system_peers` RPC | | `test-precompile-bn128-bounds` | stagenet/precompile | bn128 add/mul/pairing edge cases | | `test-receipt` | stagenet/receipt | Receipt fields, effective gas price | | `test-receipt-revert` | stagenet/receipt | Receipt for reverted transactions | | `test-evm-store-storage-growth` | stagenet/storage-growth | EVM SSTORE storage growth | | `test-txpool-future` | stagenet/txpool | Future transaction pool | | `test-txpool-pending` | stagenet/txpool | Pending transaction pool | --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
990df7ccce
commit
b45009f62d
15 changed files with 1255 additions and 0 deletions
8
test/moonwall/contracts/src/FailingConstructor.sol
Normal file
8
test/moonwall/contracts/src/FailingConstructor.sol
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
pragma solidity >=0.8.3;
|
||||
|
||||
contract FailingConstructor {
|
||||
constructor() {
|
||||
require(false);
|
||||
}
|
||||
}
|
||||
17
test/moonwall/contracts/src/StorageLoop.sol
Normal file
17
test/moonwall/contracts/src/StorageLoop.sol
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.8.2 <0.9.0;
|
||||
|
||||
contract StorageLoop {
|
||||
mapping(uint256 => uint256) public map;
|
||||
mapping(uint256 => uint256) public map2;
|
||||
|
||||
function store(uint16 n) public {
|
||||
for (uint16 i = 0; i < n; i++) {
|
||||
map[i] = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
function store2(uint256 i) public {
|
||||
map2[i] = i;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
import { describeSuite, expect } from "@moonwall/cli";
|
||||
import {
|
||||
ALITH_ADDRESS,
|
||||
CHARLETH_ADDRESS,
|
||||
baltathar,
|
||||
} from "@moonwall/util";
|
||||
|
||||
describeSuite({
|
||||
id: "D010502",
|
||||
title: "Proxy: Balances",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should accept known proxy",
|
||||
test: async () => {
|
||||
const beforeCharlieBalance = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
const { result } = await context.createBlock(
|
||||
context.polkadotJs().tx.proxy.addProxy(baltathar.address, "Balances" as any, 0)
|
||||
);
|
||||
const proxyAdded = result!.events.find(
|
||||
({ event }) => event.method === "ProxyAdded"
|
||||
);
|
||||
expect(proxyAdded).to.not.be.undefined;
|
||||
expect(proxyAdded!.event.data[2].toString()).to.be.eq("Balances"); //ProxyType
|
||||
expect(result!.events.some(({ event }) => event.method === "ExtrinsicSuccess")).to.be.true;
|
||||
|
||||
const { result: result2 } = await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.proxy.proxy(
|
||||
ALITH_ADDRESS,
|
||||
null,
|
||||
context.polkadotJs().tx.balances.transferAllowDeath(CHARLETH_ADDRESS, 100)
|
||||
)
|
||||
.signAsync(baltathar)
|
||||
);
|
||||
|
||||
const proxyExecuted = result2!.events.find(
|
||||
({ event }) => event.method === "ProxyExecuted"
|
||||
);
|
||||
expect(proxyExecuted).to.not.be.undefined;
|
||||
expect(proxyExecuted!.event.data[0].toString()).to.be.eq("Ok");
|
||||
expect(result2!.events.some(({ event }) => event.method === "ExtrinsicSuccess")).to.be
|
||||
.true;
|
||||
const afterCharlieBalance = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
expect(afterCharlieBalance - beforeCharlieBalance).to.be.eq(100n);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "shouldn't accept other proxy types",
|
||||
test: async () => {
|
||||
await context.createBlock(
|
||||
context.polkadotJs().tx.proxy.addProxy(baltathar.address, "Balances", 0)
|
||||
);
|
||||
|
||||
const { result } = await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.proxy.proxy(
|
||||
ALITH_ADDRESS,
|
||||
null,
|
||||
context.polkadotJs().tx.system.remark("0x")
|
||||
)
|
||||
.signAsync(baltathar)
|
||||
);
|
||||
|
||||
const proxyExecuted = result!.events.find(
|
||||
({ event }) => event.method === "ProxyExecuted"
|
||||
);
|
||||
expect(proxyExecuted).to.not.be.undefined;
|
||||
// Balances proxy type should not allow system.remark
|
||||
expect(proxyExecuted!.event.data[0].toString()).to.not.be.eq("Ok");
|
||||
expect(result!.events.some(({ event }) => event.method === "ExtrinsicSuccess")).to.be.true;
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
184
test/moonwall/suites/dev/stagenet/multisig/test-multisigs.ts
Normal file
184
test/moonwall/suites/dev/stagenet/multisig/test-multisigs.ts
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
|
||||
import { blake2AsHex, createKeyMulti } from "@polkadot/util-crypto";
|
||||
import { u8aToHex } from "@polkadot/util";
|
||||
import {
|
||||
ALITH_ADDRESS,
|
||||
BALTATHAR_ADDRESS,
|
||||
CHARLETH_ADDRESS,
|
||||
DOROTHY_ADDRESS,
|
||||
alith,
|
||||
baltathar,
|
||||
} from "@moonwall/util";
|
||||
|
||||
// This test cases in this suite are dependent on each other, and must be run in order.
|
||||
// TODO: Make the test cases atomic
|
||||
|
||||
describeSuite({
|
||||
id: "D022101",
|
||||
title: "Multisigs - perform multisigs operations",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it }) => {
|
||||
let threshold: number;
|
||||
let call: any;
|
||||
let encodedCall: string;
|
||||
let encodedCallHash: string;
|
||||
|
||||
// multisig accountId
|
||||
let encodedMultisigId: Uint8Array;
|
||||
let multisigId: string;
|
||||
|
||||
beforeAll(async function () {
|
||||
// set threshold and create multisig accountId
|
||||
threshold = 2;
|
||||
encodedMultisigId = createKeyMulti([ALITH_ADDRESS, BALTATHAR_ADDRESS, CHARLETH_ADDRESS], 2);
|
||||
multisigId = u8aToHex(encodedMultisigId.slice(0, 20));
|
||||
|
||||
// encode and hash the call we want to dispatch as a multisig operation
|
||||
call = context.polkadotJs().tx.balances.transferKeepAlive(DOROTHY_ADDRESS, 20);
|
||||
encodedCall = call.method.toHex();
|
||||
encodedCallHash = blake2AsHex(encodedCall);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "Should create a multisig operation with asMulti",
|
||||
test: async () => {
|
||||
// set signatories
|
||||
const otherSignatories = [BALTATHAR_ADDRESS, CHARLETH_ADDRESS];
|
||||
const block = await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.multisig.asMulti(threshold, otherSignatories, null, encodedCall, {})
|
||||
.signAsync(alith)
|
||||
);
|
||||
|
||||
// check the event 'NewMultisig' was emitted
|
||||
const records = await context.polkadotJs().query.system.events();
|
||||
const events = records.filter(
|
||||
({ event }) => event.section === "multisig" && event.method === "NewMultisig"
|
||||
);
|
||||
expect(events).to.have.lengthOf(1);
|
||||
expect(block.result!.successful).to.be.true;
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "Should be able to approve a multisig operation with approveAsMulti",
|
||||
test: async function () {
|
||||
// signatories (sorted)
|
||||
const otherSignatories = [CHARLETH_ADDRESS, ALITH_ADDRESS];
|
||||
// create a new multisig operation
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.multisig.asMulti(threshold, otherSignatories, null, encodedCall, {})
|
||||
.signAsync(alith),
|
||||
{ allowFailures: true }
|
||||
);
|
||||
|
||||
// take the info of the new multisig operation saved in storage
|
||||
const multisigInfo = await context
|
||||
.polkadotJs()
|
||||
.query.multisig.multisigs(multisigId, encodedCallHash);
|
||||
const block = await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.multisig.approveAsMulti(
|
||||
threshold,
|
||||
otherSignatories,
|
||||
multisigInfo.unwrap().when,
|
||||
encodedCallHash,
|
||||
{}
|
||||
)
|
||||
.signAsync(baltathar),
|
||||
{ allowFailures: true }
|
||||
);
|
||||
|
||||
// check the event 'MultisigApproval' was emitted
|
||||
const records = await context.polkadotJs().query.system.events();
|
||||
const events = records.filter(
|
||||
({ event }) => event.section === "multisig" && event.method === "MultisigApproval"
|
||||
);
|
||||
expect(events).to.have.lengthOf(1);
|
||||
expect(block.result!.successful).to.be.true;
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T03",
|
||||
title: "Should be able to cancel a multisig operation",
|
||||
test: async () => {
|
||||
const otherSignatories = [BALTATHAR_ADDRESS, CHARLETH_ADDRESS];
|
||||
// create a new multisig operation
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.multisig.asMulti(threshold, otherSignatories, null, encodedCall, {})
|
||||
.signAsync(alith),
|
||||
{ allowFailures: true }
|
||||
);
|
||||
|
||||
// take the info of the new multisig operation saved in storage
|
||||
const multisigInfo = await context
|
||||
.polkadotJs()
|
||||
.query.multisig.multisigs(multisigId, encodedCallHash);
|
||||
const block = await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.multisig.cancelAsMulti(
|
||||
threshold,
|
||||
otherSignatories,
|
||||
multisigInfo.unwrap().when,
|
||||
encodedCallHash
|
||||
)
|
||||
.signAsync(alith)
|
||||
);
|
||||
|
||||
const records = await context.polkadotJs().query.system.events();
|
||||
const events = records.filter(
|
||||
({ event }) => event.section === "multisig" && event.method === "MultisigCancelled"
|
||||
);
|
||||
expect(events, "event 'MultisigCancelled' was not emitted").to.have.lengthOf(1);
|
||||
expect(block.result!.successful).to.be.true;
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T04",
|
||||
title: "Should fail if signatories are out of order",
|
||||
test: async () => {
|
||||
const otherSignatories = [CHARLETH_ADDRESS, BALTATHAR_ADDRESS];
|
||||
const block = await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.multisig.asMulti(threshold, otherSignatories, null, encodedCall, {})
|
||||
.signAsync(alith),
|
||||
{ allowFailures: true }
|
||||
);
|
||||
expect(block.result!.error!.name, "signatories (they are not sorted)").to.equal(
|
||||
"SignatoriesOutOfOrder"
|
||||
);
|
||||
expect(block.result!.successful).to.be.false;
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T05",
|
||||
title: "Should fail if sender is present in signatories",
|
||||
test: async () => {
|
||||
// signatories (with sender in signatories)
|
||||
const otherSignatories = [ALITH_ADDRESS, BALTATHAR_ADDRESS];
|
||||
const block = await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.multisig.asMulti(threshold, otherSignatories, null, encodedCall, {})
|
||||
.signAsync(alith),
|
||||
{ allowFailures: true }
|
||||
);
|
||||
expect(block.result!.error!.name).to.equal("SenderInSignatories");
|
||||
expect(block.result!.successful).to.be.false;
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { customDevRpcRequest, describeSuite, expect } from "@moonwall/cli";
|
||||
|
||||
describeSuite({
|
||||
id: "D022201",
|
||||
title: "Node - RPC",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should report peer count in hex",
|
||||
test: async function () {
|
||||
// this tests that the "net_peerCount" response comes back in hex and not decimal.
|
||||
// related: frontier commits 677548c and 78fb3bc
|
||||
const result = await customDevRpcRequest("net_peerCount", []);
|
||||
|
||||
expect(result).to.be.equal("0x0");
|
||||
expect(typeof result).to.be.equal("string");
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
import { describeSuite, expect } from "@moonwall/cli";
|
||||
import { ALITH_ADDRESS, GLMR, generateKeyringPair } from "@moonwall/util";
|
||||
|
||||
describeSuite({
|
||||
id: "D022501",
|
||||
title: "Polkadot API",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should return genesis block",
|
||||
test: async function () {
|
||||
const lastHeader = await context.polkadotJs().rpc.chain.getHeader();
|
||||
expect(Number(lastHeader.number) >= 0).to.be.true;
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should return latest header number",
|
||||
test: async function () {
|
||||
await context.createBlock();
|
||||
const lastHeader = await context.polkadotJs().rpc.chain.getHeader();
|
||||
expect(lastHeader.number.toNumber()).to.be.at.least(1);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T03",
|
||||
title: "transfers should be stored on chain",
|
||||
test: async function () {
|
||||
const randomAddress = generateKeyringPair().address as `0x${string}`;
|
||||
await context.createBlock(
|
||||
context.polkadotJs().tx.balances.transferAllowDeath(randomAddress, 2n * GLMR)
|
||||
);
|
||||
|
||||
expect(BigInt(await context.viem().getBalance({ address: randomAddress }))).to.equal(
|
||||
2n * GLMR
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T04",
|
||||
title: "should appear in extrinsics",
|
||||
test: async function () {
|
||||
const randomAddress = generateKeyringPair().address as `0x${string}`;
|
||||
await context.createBlock(
|
||||
context.polkadotJs().tx.balances.transferAllowDeath(randomAddress, 2n * GLMR)
|
||||
);
|
||||
const signedBlock = await context.polkadotJs().rpc.chain.getBlock();
|
||||
|
||||
// Expecting 3 extrinsics so far:
|
||||
// timestamp, author, the parachain validation data, randomness, and the balances transfer.
|
||||
expect(signedBlock.block.extrinsics).to.be.of.length(3);
|
||||
|
||||
signedBlock.block.extrinsics.forEach((ex, index) => {
|
||||
const {
|
||||
method: { args, method, section },
|
||||
} = ex;
|
||||
const message = `${section}.${method}(${args.map((a) => a.toString()).join(", ")})`;
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
expect(message.substring(0, 13)).to.eq(`timestamp.set`);
|
||||
break;
|
||||
case 1:
|
||||
expect(message.toLocaleLowerCase()).to.match(/^randomness\.setbaberandomness/);
|
||||
break;
|
||||
case 2:
|
||||
expect(message).to.eq(
|
||||
`balances.transferAllowDeath(${randomAddress}, 2000000000000000000)`
|
||||
);
|
||||
expect(ex.signer.toString()).to.eq(ALITH_ADDRESS);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unexpected extrinsic: ${message}`);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T05",
|
||||
title: "should appear in events",
|
||||
test: async function () {
|
||||
// Generating two transfers to ensure treasury account exists
|
||||
const randomAddress = generateKeyringPair().address as `0x${string}`;
|
||||
await context.createBlock(
|
||||
context.polkadotJs().tx.balances.transferAllowDeath(randomAddress, 2n * GLMR)
|
||||
);
|
||||
|
||||
const randomAddress2 = generateKeyringPair().address as `0x${string}`;
|
||||
await context.createBlock(
|
||||
context.polkadotJs().tx.balances.transferAllowDeath(randomAddress2, 2n * GLMR)
|
||||
);
|
||||
const signedBlock = await context.polkadotJs().rpc.chain.getBlock();
|
||||
const apiAt = await context.polkadotJs().at(signedBlock.block.header.hash);
|
||||
const allRecords = await apiAt.query.system.events();
|
||||
|
||||
// map between the extrinsics and events
|
||||
signedBlock.block.extrinsics.forEach((_, index) => {
|
||||
// filter the specific events based on the phase and then the
|
||||
// index of our extrinsic in the block
|
||||
const events = allRecords
|
||||
.filter(({ phase }) => phase.isApplyExtrinsic && phase.asApplyExtrinsic.eq(index))
|
||||
.map(({ event }) => event);
|
||||
|
||||
switch (index) {
|
||||
// First 2 events:
|
||||
// timestamp.set:: system.ExtrinsicSuccess
|
||||
// randomness.setBabeRandomness:: system.ExtrinsicSuccess
|
||||
case 0:
|
||||
case 1:
|
||||
expect(events).to.be.of.length(1);
|
||||
expect(context.polkadotJs().events.system.ExtrinsicSuccess.is(events[0])).to.be.true;
|
||||
break;
|
||||
// balances.transferAllowDeath emits: system.NewAccount, balances.Endowed,
|
||||
// balances.Transfer, (other events), system.ExtrinsicSuccess
|
||||
case 2:
|
||||
log(events.map((e) => `${e.section}.${e.method}`).join(" - "));
|
||||
expect(events.length).to.be.at.least(7);
|
||||
expect(events.some((e) => context.polkadotJs().events.system.NewAccount.is(e))).to.be
|
||||
.true;
|
||||
expect(events.some((e) => context.polkadotJs().events.balances.Endowed.is(e))).to.be
|
||||
.true;
|
||||
expect(events.some((e) => context.polkadotJs().events.balances.Transfer.is(e))).to.be
|
||||
.true;
|
||||
// ExtrinsicSuccess should be the last event
|
||||
expect(
|
||||
context.polkadotJs().events.system.ExtrinsicSuccess.is(events[events.length - 1])
|
||||
).to.be.true;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unexpected extrinsic`);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { customDevRpcRequest, describeSuite, expect } from "@moonwall/cli";
|
||||
|
||||
describeSuite({
|
||||
id: "D022502",
|
||||
title: "Web3Api Information",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should include client version",
|
||||
test: async function () {
|
||||
const version = (await customDevRpcRequest("web3_clientVersion", [])) as string;
|
||||
const specName = context.polkadotJs().runtimeVersion.specName.toString();
|
||||
const specVersion = context.polkadotJs().runtimeVersion.specVersion.toString();
|
||||
const implVersion = context.polkadotJs().runtimeVersion.implVersion.toString();
|
||||
const expected = `${specName}/v${specVersion}.${implVersion}/fc-rpc-2.0.0-dev`;
|
||||
expect(version).toBe(expected);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
import { describeSuite } from "@moonwall/cli";
|
||||
import { createViemTransaction, sendRawTransaction } from "@moonwall/util";
|
||||
/*
|
||||
* These test cases trigger bugs in the bn128 precompiles which perform a from_slice()
|
||||
* call on unchecked input.
|
||||
*
|
||||
* Fixed by:
|
||||
* https://github.com/paritytech/frontier/pull/394
|
||||
*/
|
||||
|
||||
describeSuite({
|
||||
id: "D022703",
|
||||
title: "Precompiles - bn128 bounds",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should fail gracefully (case 1)",
|
||||
test: async () => {
|
||||
// some call data which will cause bn128 to be called with insufficient input. this
|
||||
// presumably was generated through fuzzing.
|
||||
const data =
|
||||
("0x608060405234801561001057600080fd5b5060008060405180608001604052807f2243525c5eda" +
|
||||
"1401003c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703815260207f6e01001d33be6da800" +
|
||||
"00002bcc35964723180eed75f91a010001007d48f195c91581526020017f18b18acfb4c2c30276db" +
|
||||
"5411000000000000000b4691610c5d3b00010001b17f81526020017f063c909c4720840cb5134cb9" +
|
||||
"f546c80200579d040100d32efc0d288197f37266815246475b6100bf61044d505b6040604b808460" +
|
||||
"006007600019f1925082610142576000000000acd401000000000000000000000000000000000000" +
|
||||
"000000000000000000008152600401808060200182810300192c748252601e8152602001887f656c" +
|
||||
"6c967074000381327572766520616464ad74696f6e206661696c6564000081525060200191500000" +
|
||||
"000000000009fd5b7f2bd3e6d0f3b142924f5ca7b49ce5b9d585420400ae5648e61d02268b1a0a9f" +
|
||||
"b7816000600202020202020202020202020202020202fd0202020203020202020202020202020202" +
|
||||
"0202fb02020a02020202020202020202020202020202020202020202020202020202020202020202" +
|
||||
"02020202020200000000000000000a1c000000000000000000000000000000000000000901010037" +
|
||||
"190100000000000000000000f81a0100000002020202020202020202020202020202020202028a30" +
|
||||
"a82123b27db75200aedc4a45a0e84fbd1f9f3621350bb778119630350eb7a7e613058daf51e9f514" +
|
||||
"8ea65715eaac3d8019f80498112fc4860a020202020202020202fd02020202020202020202020202" +
|
||||
"02020202020202020202020202020202020202020202020202020202020202020202020202020212" +
|
||||
"02020202020202020202010202fd0202020202020202020202020202020202020202020202020202" +
|
||||
"020202020202020202020202005f02d2020202020202020202020202020202020202020202020202" +
|
||||
"02020202020202020202020302020202020202020202020202020202020202020202020202020202" +
|
||||
"0302020202020202020202020202") as `0x${string}`;
|
||||
|
||||
const tx = await createViemTransaction(context, {
|
||||
to: "0x0000000000000000000000000000000000000007",
|
||||
data,
|
||||
skipEstimation: true,
|
||||
});
|
||||
|
||||
await sendRawTransaction(context, tx);
|
||||
|
||||
// we expect that the node hasn't crashed by here. without a fix, the previous web3 request
|
||||
// would have been sufficient to crash our node. now it fails with "ExhaustsResources". if
|
||||
// we can create a block, we must not have crashed.
|
||||
await context.createBlock();
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should fail gracefully (case 2)",
|
||||
test: async () => {
|
||||
// similar to the above call data, although triggers a slightly different bug
|
||||
|
||||
const tx = await createViemTransaction(context, {
|
||||
to: "0x0000000000000000000000000000000000000007",
|
||||
data: "0x0000000000000000000000000000000000000000050000000000008303d0300d901401",
|
||||
skipEstimation: true,
|
||||
});
|
||||
|
||||
await sendRawTransaction(context, tx);
|
||||
|
||||
// we expect that the node hasn't crashed by here. without a fix, the previous web3 request
|
||||
// would have been sufficient to crash our node. now it fails with "ExhaustsResources". if
|
||||
// we can create a block, we must not have crashed.
|
||||
await context.createBlock();
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
257
test/moonwall/suites/dev/stagenet/proxy/test-proxy.ts
Normal file
257
test/moonwall/suites/dev/stagenet/proxy/test-proxy.ts
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
import { beforeEach, describeSuite, expect } from "@moonwall/cli";
|
||||
import {
|
||||
ALITH_ADDRESS,
|
||||
CHARLETH_ADDRESS,
|
||||
type KeyringPair,
|
||||
alith,
|
||||
generateKeyringPair,
|
||||
} from "@moonwall/util";
|
||||
|
||||
// In these tests Alith will allow signer to perform calls on her behalf.
|
||||
// Charleth is used as a target account when making transfers.
|
||||
|
||||
describeSuite({
|
||||
id: "D022902",
|
||||
title: "Proxy - proxy",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
let signer: KeyringPair;
|
||||
|
||||
beforeEach(async () => {
|
||||
signer = generateKeyringPair("ethereum");
|
||||
|
||||
await context.createBlock(
|
||||
context.polkadotJs().tx.balances.transferAllowDeath(signer.address, 5n * 10n ** 18n)
|
||||
);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "shouldn't accept unknown proxy",
|
||||
test: async function () {
|
||||
const beforeCharlethBalance = await context
|
||||
.viem()
|
||||
.getBalance({ address: CHARLETH_ADDRESS });
|
||||
|
||||
const expectEvents = [context.polkadotJs().events.system.ExtrinsicFailed];
|
||||
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.proxy.proxy(
|
||||
ALITH_ADDRESS,
|
||||
null,
|
||||
context.polkadotJs().tx.balances.transferAllowDeath(CHARLETH_ADDRESS, 100)
|
||||
)
|
||||
.signAsync(signer),
|
||||
{ expectEvents, signer: alith, allowFailures: true }
|
||||
);
|
||||
const afterCharlethBalance = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
expect(afterCharlethBalance - beforeCharlethBalance).to.be.eq(0n);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should accept known proxy",
|
||||
test: async () => {
|
||||
const beforeCharlethBalance = await context
|
||||
.viem()
|
||||
.getBalance({ address: CHARLETH_ADDRESS });
|
||||
|
||||
const events1 = [
|
||||
context.polkadotJs().events.system.ExtrinsicSuccess,
|
||||
context.polkadotJs().events.proxy.ProxyAdded,
|
||||
];
|
||||
|
||||
const { result } = await context.createBlock(
|
||||
context.polkadotJs().tx.proxy.addProxy(signer.address, "Any", 0),
|
||||
{ signer: alith, expectEvents: events1 }
|
||||
);
|
||||
const proxyAdded = result?.events.find(({ event }) =>
|
||||
context.polkadotJs().events.proxy.ProxyAdded.is(event)
|
||||
);
|
||||
expect(proxyAdded).to.not.be.undefined;
|
||||
expect(proxyAdded!.event.data[2].toString()).to.be.eq("Any"); //ProxyType
|
||||
|
||||
const events2 = [
|
||||
context.polkadotJs().events.system.ExtrinsicSuccess,
|
||||
context.polkadotJs().events.proxy.ProxyExecuted,
|
||||
];
|
||||
|
||||
const { result: result2 } = await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.proxy.proxy(
|
||||
alith.address,
|
||||
null,
|
||||
context.polkadotJs().tx.balances.transferAllowDeath(CHARLETH_ADDRESS, 100)
|
||||
)
|
||||
.signAsync(signer),
|
||||
{ signer: alith, expectEvents: events2 }
|
||||
);
|
||||
const proxyExecuted = result2?.events.find(({ event }) =>
|
||||
context.polkadotJs().events.proxy.ProxyExecuted.is(event)
|
||||
);
|
||||
expect(proxyExecuted).to.not.be.undefined;
|
||||
expect(proxyExecuted!.event.data[0].toString()).to.be.eq("Ok");
|
||||
const afterCharlethBalance = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
expect(afterCharlethBalance - beforeCharlethBalance).to.be.eq(100n);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T03",
|
||||
title: "shouldn't accept removed proxy",
|
||||
test: async () => {
|
||||
const beforeCharlethBalance = await context
|
||||
.viem()
|
||||
.getBalance({ address: CHARLETH_ADDRESS });
|
||||
|
||||
await context.createBlock(
|
||||
context.polkadotJs().tx.proxy.addProxy(signer.address, "Any", 0),
|
||||
{ signer: alith, allowFailures: false }
|
||||
);
|
||||
|
||||
await context.createBlock(
|
||||
context.polkadotJs().tx.proxy.removeProxy(signer.address, "Any", 0),
|
||||
{ signer: alith, allowFailures: false }
|
||||
);
|
||||
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.proxy.proxy(
|
||||
alith.address,
|
||||
null,
|
||||
context.polkadotJs().tx.balances.transferAllowDeath(CHARLETH_ADDRESS, 100)
|
||||
)
|
||||
.signAsync(signer),
|
||||
{ signer: alith, expectEvents: [context.polkadotJs().events.system.ExtrinsicFailed] }
|
||||
);
|
||||
const afterCharlethBalance = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
expect(afterCharlethBalance - beforeCharlethBalance).to.be.eq(0n);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T04",
|
||||
title: "shouldn't accept instant for delayed proxy",
|
||||
test: async () => {
|
||||
const beforeCharlethBalance = await context
|
||||
.viem()
|
||||
.getBalance({ address: CHARLETH_ADDRESS });
|
||||
|
||||
await context.createBlock(
|
||||
context.polkadotJs().tx.proxy.addProxy(signer.address, "Any", 2),
|
||||
{ signer: alith, allowFailures: false }
|
||||
);
|
||||
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.proxy.proxy(
|
||||
alith.address,
|
||||
null,
|
||||
context.polkadotJs().tx.balances.transferAllowDeath(CHARLETH_ADDRESS, 100)
|
||||
)
|
||||
.signAsync(signer),
|
||||
{ signer: alith, expectEvents: [context.polkadotJs().events.system.ExtrinsicFailed] }
|
||||
);
|
||||
const afterCharlethBalance = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
expect(afterCharlethBalance - beforeCharlethBalance).to.be.eq(0n);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T05",
|
||||
title: "shouldn't accept early delayed proxy",
|
||||
test: async () => {
|
||||
const beforeCharlethBalance = await context
|
||||
.viem()
|
||||
.getBalance({ address: CHARLETH_ADDRESS });
|
||||
const { result } = await context.createBlock(
|
||||
context.polkadotJs().tx.proxy.addProxy(signer.address, "Any", 6),
|
||||
{ signer: alith, allowFailures: false }
|
||||
);
|
||||
result?.events.forEach(({ event }) => log(`1${event.method}(${event.data})`));
|
||||
|
||||
const transfer = context.polkadotJs().tx.balances.transferAllowDeath(CHARLETH_ADDRESS, 100);
|
||||
|
||||
const { result: result2 } = await context.createBlock(
|
||||
context.polkadotJs().tx.proxy.announce(alith.address, transfer.hash).signAsync(signer),
|
||||
{
|
||||
signer: alith,
|
||||
expectEvents: [context.polkadotJs().events.proxy.Announced],
|
||||
allowFailures: false,
|
||||
}
|
||||
);
|
||||
result2?.events.forEach(({ event }) => log(`2${event.method}(${event.data})`));
|
||||
|
||||
const { result: result3 } = await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.proxy.proxyAnnounced(signer.address, alith.address, null, transfer)
|
||||
.signAsync(signer),
|
||||
{
|
||||
signer: alith,
|
||||
expectEvents: [context.polkadotJs().events.system.ExtrinsicFailed],
|
||||
}
|
||||
);
|
||||
result3?.events.forEach(({ event }) => log(`3${event.method}(${event.data})`));
|
||||
const afterCharlethBalance = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
expect(afterCharlethBalance - beforeCharlethBalance).to.be.eq(0n);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T06",
|
||||
title: "should accept on-time delayed proxy ",
|
||||
test: async () => {
|
||||
const beforeCharlethBalance = await context
|
||||
.viem()
|
||||
.getBalance({ address: CHARLETH_ADDRESS });
|
||||
await context.createBlock(
|
||||
context.polkadotJs().tx.proxy.addProxy(signer.address, "Any", 2),
|
||||
{ signer: alith, allowFailures: false }
|
||||
);
|
||||
|
||||
const transfer = context.polkadotJs().tx.balances.transferAllowDeath(CHARLETH_ADDRESS, 100);
|
||||
const u8a = transfer.method.toU8a();
|
||||
const transfer_hash = transfer.registry.hash(u8a).toHex();
|
||||
|
||||
const { result: result2 } = await context.createBlock(
|
||||
context.polkadotJs().tx.proxy.announce(alith.address, transfer_hash).signAsync(signer),
|
||||
{
|
||||
signer: alith,
|
||||
expectEvents: [context.polkadotJs().events.proxy.Announced],
|
||||
allowFailures: false,
|
||||
}
|
||||
);
|
||||
const announced = result2?.events.find(({ event }) =>
|
||||
context.polkadotJs().events.proxy.Announced.is(event)
|
||||
);
|
||||
expect(announced).to.not.be.undefined;
|
||||
expect(announced!.event.data[2].toHex()).to.eq(transfer_hash);
|
||||
|
||||
await context.createBlock();
|
||||
await context.createBlock();
|
||||
|
||||
// On time.
|
||||
const { result: result3 } = await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.proxy.proxyAnnounced(signer.address, alith.address, null, transfer)
|
||||
.signAsync(signer),
|
||||
{
|
||||
signer: alith,
|
||||
expectEvents: [context.polkadotJs().events.proxy.ProxyExecuted],
|
||||
allowFailures: false,
|
||||
}
|
||||
);
|
||||
const afterCharlethBalance = await context.viem().getBalance({ address: CHARLETH_ADDRESS });
|
||||
expect(afterCharlethBalance - beforeCharlethBalance).to.be.eq(100n);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import { describeSuite, expect } from "@moonwall/cli";
|
||||
import { getAddress } from "viem";
|
||||
|
||||
describeSuite({
|
||||
id: "D023101",
|
||||
title: "Receipt - Revert",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should generate a receipt for a reverted transaction",
|
||||
test: async function () {
|
||||
const { hash } = await context.deployContract!("FailingConstructor", { gas: 300000n });
|
||||
const receipt = await context.viem().getTransactionReceipt({ hash });
|
||||
|
||||
expect(receipt.status).toBe("reverted");
|
||||
expect(receipt.blockNumber).toBe(1n);
|
||||
expect(getAddress(receipt.contractAddress!)).toBe(
|
||||
getAddress("0xc01Ee7f10EA4aF4673cFff62710E1D7792aBa8f3")
|
||||
);
|
||||
expect(receipt.cumulativeGasUsed).toBe(54604n);
|
||||
expect(getAddress(receipt.from!)).toBe(
|
||||
getAddress("0xf24ff3a9cf04c71dbc94d0b566f7a27b94566cac")
|
||||
);
|
||||
expect(receipt.gasUsed).toBe(54604n);
|
||||
expect(receipt.logs).toStrictEqual([]);
|
||||
expect(receipt.transactionHash).toBe(hash);
|
||||
expect(receipt.to).toBe(null);
|
||||
expect(receipt.transactionIndex).toBe(0);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
61
test/moonwall/suites/dev/stagenet/receipt/test-receipt.ts
Normal file
61
test/moonwall/suites/dev/stagenet/receipt/test-receipt.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import { beforeAll, describeSuite, expect } from "@moonwall/cli";
|
||||
import { BALTATHAR_ADDRESS, alith } from "@moonwall/util";
|
||||
|
||||
describeSuite({
|
||||
id: "D023103",
|
||||
title: "Receipt - Contract",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
let txHash: string;
|
||||
let eventContract: `0x${string}`;
|
||||
|
||||
beforeAll(async () => {
|
||||
const { contractAddress, hash } = await context.deployContract!("EventEmitter");
|
||||
eventContract = contractAddress;
|
||||
txHash = hash;
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "Should generate receipt",
|
||||
test: async function () {
|
||||
const block = await context.viem().getBlock({ blockNumber: 1n });
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: txHash as `0x${string}` });
|
||||
|
||||
expect(receipt.blockHash).toBe(block.hash);
|
||||
expect(receipt.blockNumber).toBe(block.number);
|
||||
expect(receipt.from).toBe(alith.address.toLowerCase());
|
||||
expect(receipt.logs.length).toBe(1);
|
||||
expect(receipt.logs[0].address).toBe(eventContract);
|
||||
expect(receipt.logs[0].blockHash).toBe(block.hash);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should calculate effective gas price",
|
||||
test: async function () {
|
||||
const maxFeePerGas = 10_000_000_000n * 2n;
|
||||
|
||||
const rawTxn = await context.createTxn!({
|
||||
gas: 21000n,
|
||||
libraryType: "viem",
|
||||
maxFeePerGas: maxFeePerGas,
|
||||
maxPriorityFeePerGas: maxFeePerGas,
|
||||
to: BALTATHAR_ADDRESS,
|
||||
data: "0x",
|
||||
txnType: "eip1559",
|
||||
});
|
||||
await context.createBlock(rawTxn);
|
||||
|
||||
const block = await context.viem().getBlock();
|
||||
const receipt = await context
|
||||
.viem()
|
||||
.getTransactionReceipt({ hash: block.transactions[0] as `0x${string}` });
|
||||
expect(receipt.effectiveGasPrice).to.be.eq(maxFeePerGas);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// TODO: Constants (storage growth ratios, limits) may need adjustment for DataHaven's runtime configuration
|
||||
import {
|
||||
TransactionTypes,
|
||||
beforeAll,
|
||||
deployCreateCompiledContract,
|
||||
describeSuite,
|
||||
} from "@moonwall/cli";
|
||||
import { createEthersTransaction } from "@moonwall/util";
|
||||
import { expectEVMResult, expectOk } from "../../../../helpers";
|
||||
import { type Abi, encodeFunctionData } from "viem";
|
||||
|
||||
describeSuite({
|
||||
id: "D023403",
|
||||
title: "Storage growth limit - New Entries",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
let storageLoopAddress: `0x${string}`;
|
||||
let storageLoopAbi: Abi;
|
||||
// Number of bytes added to storage for a new entry.
|
||||
const ACCOUNT_STORAGE_SIZE = 116;
|
||||
// Ratio of gas to storage growth. (BlockGasLimit (15_000_000) / BlockStorageLimit (40kb))
|
||||
const GAS_LIMIT_STORAGE_GROWTH_RATIO = 366;
|
||||
beforeAll(async () => {
|
||||
const { contractAddress, abi } = await deployCreateCompiledContract(context, "StorageLoop");
|
||||
storageLoopAddress = contractAddress;
|
||||
storageLoopAbi = abi;
|
||||
|
||||
await context.createBlock();
|
||||
});
|
||||
|
||||
for (const txnType of TransactionTypes) {
|
||||
it({
|
||||
id: `T0${TransactionTypes.indexOf(txnType) + 1}`,
|
||||
title: "should out of gas when gas provided is not enough to cover storage growth",
|
||||
test: async function () {
|
||||
// Tx is creating 5 new storage entries. So, required gas is:
|
||||
// (5 * ACCOUNT_STORAGE_SIZE) * GAS_LIMIT_STORAGE_GROWTH_RATIO = 212_280
|
||||
// Execute tx with insufficient gas limit
|
||||
const rawSigned = await createEthersTransaction(context, {
|
||||
to: storageLoopAddress,
|
||||
data: encodeFunctionData({
|
||||
abi: storageLoopAbi,
|
||||
functionName: "store",
|
||||
// for each transaction type, we add 5 new storage entries
|
||||
args: [5 + 5 * TransactionTypes.indexOf(txnType)],
|
||||
}),
|
||||
gasLimit: 212_270,
|
||||
});
|
||||
|
||||
const { result } = await context.createBlock(rawSigned);
|
||||
// Check that the transaction failed with an out of gas error
|
||||
expectEVMResult(result!.events, "Error", "OutOfGas");
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: `T0${TransactionTypes.indexOf(txnType) + 4}`,
|
||||
title: "should successfully execute when updating existing storage entries (no growth)",
|
||||
test: async function () {
|
||||
// Update 5 existing storage entries. So, required gas should be less than 212_280
|
||||
const rawSigned = await createEthersTransaction(context, {
|
||||
to: storageLoopAddress,
|
||||
data: encodeFunctionData({
|
||||
abi: storageLoopAbi,
|
||||
functionName: "store",
|
||||
args: [5],
|
||||
}),
|
||||
gasLimit: 50_000,
|
||||
});
|
||||
|
||||
await expectOk(context.createBlock(rawSigned));
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
123
test/moonwall/suites/dev/stagenet/sudo/test-sudo.ts
Normal file
123
test/moonwall/suites/dev/stagenet/sudo/test-sudo.ts
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
import { describeSuite, expect } from "@moonwall/cli";
|
||||
import {
|
||||
ALITH_ADDRESS,
|
||||
DEFAULT_GENESIS_BALANCE,
|
||||
baltathar,
|
||||
generateKeyringPair,
|
||||
} from "@moonwall/util";
|
||||
import { ALITH_GENESIS_TRANSFERABLE_BALANCE, verifyLatestBlockFees } from "../../../../helpers";
|
||||
import { CHARLETH_ADDRESS, ETHAN_ADDRESS } from "@moonwall/util";
|
||||
|
||||
describeSuite({
|
||||
id: "D023601",
|
||||
title: "Sudo - successful forceSetBalance",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it }) => {
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should be able to call sudo with the right account",
|
||||
test: async function () {
|
||||
const { result } = await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.sudo.sudo(context.polkadotJs().tx.balances.forceSetBalance(ETHAN_ADDRESS, 0))
|
||||
);
|
||||
|
||||
const account = await context.polkadotJs().query.system.account(ETHAN_ADDRESS);
|
||||
expect(account.data.free.toBigInt()).toBe(0n);
|
||||
|
||||
// DataHaven has 1 more event (NewChallengeSeed) than Moonbeam,
|
||||
// coming from the StorageHub ProofsDealer pallet.
|
||||
expect(result!.events.length).to.eq(8);
|
||||
console.log(result!.events.map((e) => e.event.toHuman()));
|
||||
expect(context.polkadotJs().events.balances.BalanceSet.is(result!.events[3].event)).to.be
|
||||
.true;
|
||||
expect(context.polkadotJs().events.sudo.Sudid.is(result!.events[4].event)).to.be.true;
|
||||
expect(context.polkadotJs().events.balances.Deposit.is(result!.events[5].event)).to.be.true;
|
||||
expect(context.polkadotJs().events.system.ExtrinsicSuccess.is(result!.events[7].event)).to
|
||||
.be.true;
|
||||
|
||||
expect(
|
||||
await context.viem().getBalance({ address: ALITH_ADDRESS }),
|
||||
"diff should be null for sudo - funds are sent back"
|
||||
).to.equal(ALITH_GENESIS_TRANSFERABLE_BALANCE);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should charge the correct amount of gas when calling sudo",
|
||||
test: async function () {
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.sudo.sudo(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.balances.forceSetBalance(CHARLETH_ADDRESS, DEFAULT_GENESIS_BALANCE)
|
||||
)
|
||||
);
|
||||
|
||||
await verifyLatestBlockFees(context);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T03",
|
||||
title: "should NOT be able to call sudo with another account than sudo account",
|
||||
test: async function () {
|
||||
const baltathar_before = await context.polkadotJs().query.system.account(CHARLETH_ADDRESS);
|
||||
const { result } = await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.sudo.sudo(context.polkadotJs().tx.balances.forceSetBalance(CHARLETH_ADDRESS, 0))
|
||||
.signAsync(baltathar),
|
||||
{ allowFailures: true }
|
||||
);
|
||||
|
||||
// Check that balance didn't change
|
||||
const account = await context.polkadotJs().query.system.account(CHARLETH_ADDRESS);
|
||||
expect(account.data.free.toBigInt()).toBe(DEFAULT_GENESIS_BALANCE);
|
||||
|
||||
expect(result!.events.length === 8).to.be.true;
|
||||
expect(context.polkadotJs().events.system.NewAccount.is(result!.events[3].event)).to.be
|
||||
.true;
|
||||
expect(context.polkadotJs().events.balances.Endowed.is(result!.events[4].event)).to.be.true;
|
||||
expect(context.polkadotJs().events.system.ExtrinsicFailed.is(result!.events[7].event)).to.be
|
||||
.true;
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T04",
|
||||
title: "should not be able to call sudo with no funds",
|
||||
test: async function () {
|
||||
const newSigner = generateKeyringPair();
|
||||
|
||||
await context.createBlock(context.polkadotJs().tx.sudo.setKey(newSigner.address), {
|
||||
allowFailures: false,
|
||||
});
|
||||
|
||||
expect((await context.polkadotJs().query.sudo.key()).unwrap().toString()).toBe(
|
||||
newSigner.address
|
||||
);
|
||||
|
||||
await expect(
|
||||
async () =>
|
||||
await context.createBlock(
|
||||
context
|
||||
.polkadotJs()
|
||||
.tx.sudo.sudo(context.polkadotJs().tx.balances.forceSetBalance(CHARLETH_ADDRESS, 0))
|
||||
.signAsync(newSigner)
|
||||
)
|
||||
).rejects.toThrowError(
|
||||
"1010: Invalid Transaction: Inability to pay some fees , e.g. account balance too low"
|
||||
);
|
||||
|
||||
expect(await context.viem().getBalance({ address: CHARLETH_ADDRESS })).to.equal(
|
||||
DEFAULT_GENESIS_BALANCE
|
||||
);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
import { beforeAll, describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
|
||||
import { alith, createEthersTransaction, sendRawTransaction } from "@moonwall/util";
|
||||
import { encodeDeployData, toHex } from "viem";
|
||||
|
||||
describeSuite({
|
||||
id: "D023802",
|
||||
title: "TxPool - Future Ethereum transaction",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
let txHash: string;
|
||||
let deployData: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
const { abi, bytecode } = fetchCompiledContract("MultiplyBy7");
|
||||
deployData = encodeDeployData({
|
||||
abi,
|
||||
bytecode,
|
||||
});
|
||||
|
||||
const rawTxn = await createEthersTransaction(context, {
|
||||
data: deployData,
|
||||
gasLimit: 1048576,
|
||||
nonce: 1, // future nonce
|
||||
});
|
||||
txHash = await sendRawTransaction(context, rawTxn);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should appear in the txpool inspection",
|
||||
test: async function () {
|
||||
const inspect = (await context
|
||||
.viem()
|
||||
.transport.request({ method: "txpool_inspect" })) as any;
|
||||
// web3 rpc returns lowercase
|
||||
const data = inspect.queued[alith.address.toLowerCase()][toHex(1)];
|
||||
expect(data).to.not.be.undefined;
|
||||
expect(data).to.be.equal(
|
||||
"0x0000000000000000000000000000000000000000: 0 wei + 1048576 gas x 10000000000 wei"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should appear in the txpool content",
|
||||
test: async function () {
|
||||
const content = (await context
|
||||
.viem()
|
||||
.transport.request({ method: "txpool_content" })) as any;
|
||||
// web3 rpc returns lowercase
|
||||
const data = content.queued[alith.address.toLowerCase()][toHex(1)];
|
||||
expect(data).toMatchObject({
|
||||
blockHash: null,
|
||||
blockNumber: null,
|
||||
from: alith.address.toLowerCase(),
|
||||
gas: "0x100000",
|
||||
gasPrice: "0x2540be400",
|
||||
hash: txHash,
|
||||
input: deployData,
|
||||
nonce: toHex(1),
|
||||
to: null,
|
||||
transactionIndex: null,
|
||||
value: "0x0",
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
import { beforeAll, describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
|
||||
import { ALITH_ADDRESS, createEthersTransaction, sendRawTransaction } from "@moonwall/util";
|
||||
import { encodeDeployData, toHex } from "viem";
|
||||
|
||||
describeSuite({
|
||||
id: "D023807",
|
||||
title: "TxPool - Pending Ethereum transaction",
|
||||
foundationMethods: "dev",
|
||||
testCases: ({ context, it, log }) => {
|
||||
let txHash: string;
|
||||
|
||||
beforeAll(async () => {
|
||||
const { abi, bytecode } = fetchCompiledContract("MultiplyBy7");
|
||||
const deployData = encodeDeployData({
|
||||
abi,
|
||||
bytecode,
|
||||
});
|
||||
|
||||
const rawTxn = await createEthersTransaction(context, {
|
||||
data: deployData,
|
||||
gasLimit: 1048576,
|
||||
nonce: 0,
|
||||
});
|
||||
txHash = await sendRawTransaction(context, rawTxn);
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T01",
|
||||
title: "should appear in the txpool inspection",
|
||||
test: async function () {
|
||||
const inspect = (await context
|
||||
.viem()
|
||||
.transport.request({ method: "txpool_inspect" })) as any;
|
||||
|
||||
// web3 rpc returns lowercase
|
||||
const data = inspect.pending[ALITH_ADDRESS.toLowerCase()][toHex(0)];
|
||||
expect(data).to.not.be.undefined;
|
||||
expect(data).to.be.equal(
|
||||
"0x0000000000000000000000000000000000000000: 0 wei + 1048576 gas x 10000000000 wei"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T02",
|
||||
title: "should be marked as pending",
|
||||
test: async function () {
|
||||
const pendingTransaction = await context
|
||||
.viem()
|
||||
.getTransaction({ hash: txHash as `0x${string}` });
|
||||
|
||||
// pending transactions do not know yet to which block they belong to
|
||||
expect(pendingTransaction).to.include({
|
||||
blockNumber: null,
|
||||
hash: txHash,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
it({
|
||||
id: "T03",
|
||||
title: "should appear in the txpool content",
|
||||
test: async function () {
|
||||
const content = (await context
|
||||
.viem()
|
||||
.transport.request({ method: "txpool_content" })) as any;
|
||||
|
||||
// web3 rpc returns lowercase
|
||||
const data = content.pending[ALITH_ADDRESS.toLowerCase()][toHex(0)];
|
||||
expect(data).to.include({
|
||||
blockHash: null,
|
||||
blockNumber: null,
|
||||
from: ALITH_ADDRESS.toLowerCase(),
|
||||
gas: "0x100000",
|
||||
gasPrice: "0x2540be400",
|
||||
hash: txHash,
|
||||
nonce: toHex(0),
|
||||
to: null,
|
||||
value: "0x0",
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
Loading…
Reference in a new issue