In writing some integration tests recently, I’ve tried spinning up several hundred canisters in parallel.
When I’m spinning up canisters in preparation for the tests, I execute the following function
export async function batchDeployCanisters(
numCanisters: number,
withIcp: number = 0.1
): Promise<Principal[]> {
const canisters = await Promise.all(
[...Array(numCanisters)].map(
async (): Promise<Principal> =>
new Promise((resolve, reject) => {
exec(
`dfx ledger create-canister --amount ${withIcp}`,
(err, stdout) => {
if (err) {
reject(err);
return;
}
const canister = stdout
.toString()
.match(/Canister created with id: "([a-z0-9-]+)"/)[1];
resolve(Principal.fromText(canister));
}
);
})
)
);
return canisters;
}
And while a few canisters are created, for the majority of create-canister
attempts I receive many of the following error.
Burning of 0.01000000 Token ICPTs from subaccount 0a00000000000000160101000000000000000000000000000000000000000000 failed with code 5: "IC0503: Canister ryjl3-tyaaa-aaaaa-aaaba-ca> trapped explicitly: transaction is a duplicate of another transaction in block 470"
(for reference, ryjl3-tyaaa-aaaaa-aaaba-cai
is the nns-ledger
canister).
Am I overloading the ledger’s capacity per block? Do I need batch these requests to slow down the spin up of canisters in my local testing? Would I receive the same error on main net if I flooded the ledger with create-canister
requests?
One puzzle to me however is the error message - why is it saying that each of these create-canister
requests are duplicate transactions?