Last active
May 11, 2021 06:08
-
-
Save itzmeanjan/9b8cdff401081e593f8a477ecba144f4 to your computer and use it in GitHub Desktop.
Submit bulk Tx @ Matic DA Blockchain
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { ApiPromise, WsProvider, Keyring } = require('@polkadot/api') | |
const { Buffer } = require('buffer') | |
const { createWriteStream } = require('fs') | |
const BATCH = process.env.BATCH || 100 // these many tx(s) to be attempted to be submitted | |
const PAYLOAD = process.env.PAYLOAD || 512 // in terms of bytes | |
const WSURL = process.env.WSURL || 'ws://localhost:9944' | |
// To be initialized, after `setUp` is called | |
let handle | |
const fd = createWriteStream('./tx.log', { flags: 'a' }) | |
const keyring = new Keyring({ type: 'sr25519' }) | |
// Initializing Polkadot API for using it with Matic DA Blockchain | |
const setUp = async _ => { | |
const provider = new WsProvider(WSURL) | |
const api = await ApiPromise.create({ | |
provider, types: { | |
ExtrinsicsRoot: { | |
hash: 'Hash', | |
commitment: 'Vec<u8>' | |
}, | |
Header: { | |
parentHash: 'Hash', | |
number: 'Compact<BlockNumber>', | |
stateRoot: 'Hash', | |
extrinsicsRoot: 'ExtrinsicsRoot', | |
digest: 'Digest' | |
} | |
} | |
}) | |
return api | |
} | |
// Generates random byte array of specified size | |
const generateData = size => { | |
let buffer = Buffer.alloc(size) | |
for (let i = 0; i < size; i++) { | |
buffer.writeUInt8(Math.floor(Math.random() * 256), i) | |
} | |
return buffer.toString('hex') | |
} | |
// Attempts to calculate nonce of account | |
const getNonce = async account => { | |
try { | |
const nonce = await handle.rpc.system.accountNextIndex(account.address) | |
return nonce | |
} catch (e) { | |
console.error(e.toString()) | |
return 0 | |
} | |
} | |
// Sends a tx & tracks its life cycle until it becomes finalized | |
const sendTx = (sender, nonce, size) => new Promise(async (res, rej) => { | |
try { | |
const unsub = await handle.tx.templateModule | |
.submitData(generateData(size)) | |
.signAndSend(sender, { nonce }, async result => { | |
if (result.status.isReady) { | |
console.log(`Tx with nonce ${nonce} [ READY ]`) | |
return | |
} | |
// Wait until tx is included in block | |
if (result.status.isInBlock) { | |
console.log(`Tx with nonce ${nonce} in ${result.status.asInBlock} [ INCLUDED ]`) | |
unsub() | |
res(result.status.asInBlock) | |
} | |
}) | |
} catch (e) { | |
rej(e) | |
} | |
}) | |
// Sends `BATCH` many tx(s), where each attempts to submit `PAYLOAD` bytes | |
// data | |
const sendTxs = (sender, options) => new Promise(async (res, rej) => { | |
let batch = BATCH | |
let payload = PAYLOAD | |
if (options !== undefined && options !== null) { | |
batch = options.BATCH || BATCH | |
payload = options.PAYLOAD || PAYLOAD | |
} | |
let promises = [] | |
let nonce = BigInt(await getNonce(sender)) | |
for (let i = 0; i < batch; i++) { | |
promises.push(sendTx(sender, nonce, payload)) | |
nonce += 1n // keep incrementing nonce before sending next tx | |
} | |
// Creating an easy to digest stat of how many tx(s) got included | |
// in each block | |
// | |
// @note We attempted to send `BATCH` tx(s) in a single go | |
// and may be not all of them got included in same block | |
await Promise.all(promises).then(v => { | |
res(v.reduce((acc, cur) => { | |
if (cur in acc) { | |
acc[cur]++ | |
} else { | |
acc[cur] = 1 | |
} | |
return acc | |
}, {})) | |
}).catch(rej) | |
}) | |
// Main entry script, for submitting bulk tx(s) | |
const main = async _ => { | |
// Initialising global variable, so all tx sending can use this same API instance | |
handle = await setUp() | |
const alice = keyring.addFromUri('//Alice', { name: 'Alice default' }) | |
const bob = keyring.addFromUri('//Bob', { name: 'Bob default' }) | |
for (let batch = 1; batch < 10000; batch++) { | |
for (let payload = 1; payload < 2048; payload++) { | |
const options = { BATCH: batch, PAYLOAD: payload } | |
await Promise.all([sendTxs(alice, options), sendTxs(bob, options)]).then(v => { | |
const stat = { | |
...options, | |
stat: v.reduce((acc, cur) => { | |
Object.keys(cur).forEach(v => { | |
if (v in acc) { | |
acc[v] += cur[v] | |
} else { | |
acc[v] = cur[v] | |
} | |
}) | |
return acc | |
}, {}), | |
...{ time: new Date().toUTCString() } | |
} | |
console.log(`✅ Tx(s) finalized : 👇`) | |
console.log(stat) | |
fd.write(`${JSON.stringify(stat, null, 2)}\n`) | |
}).catch(e => { console.error(e.toString()); fd.close(); process.exit(1) }) | |
} | |
} | |
} | |
main().catch((e) => { console.error(e.toString()); process.exit(1); }) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "matic-da-bulk-tx", | |
"version": "1.0.0", | |
"description": "", | |
"main": "index.js", | |
"scripts": { | |
"start": "node index.js", | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"keywords": [], | |
"author": "Anjan Roy<[email protected]>", | |
"license": "ISC", | |
"dependencies": { | |
"@polkadot/api": "^4.0.3" | |
} | |
} |
Updated script attempts to run for multiple possible combinations of BATCH_SIZE
& PAYLOAD_SIZE
& keeps result in tx.log
file in JSON serialised form in append only mode.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This script is supposed to be used for submitting bulk tx in Matic's DA blockchain.
Usage
ws://localhost:9944
to be usedindex.js
withIt'll attempt to generate random byte array payload of size 512 bytes ( by default ) & submit 1024 ( by default ) tx(s) in a single go. After all those 1024 tx(s) get confirmed, it'll start next iteration.