-
Notifications
You must be signed in to change notification settings - Fork 146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Feature] No access to accounts in preSetup #38
Comments
@MarvinJanssen can you give an example of things you would like to do in |
Deploy mock contracts or send initialising calls to contracts. Some of these things could be alleviated with deploy scripts but anything that is statically coded into the contract has to be present before Clarinet does its chain setup. Say that you are working on a prediction market that uses open-oracle, you'd want to mock that oracle in test. |
What if we would split
If it would be possible, we could start writing like tests like this: Clarinet.test('Super important test', (chain: Chain, accounts: Accounts) => {
let mockOracle = new MockContract("imaginary-oracle-v1", "SP000000000000000000002Q6VF78");
mockOracle.publicFn("price",{
inputs: [typeDefs.ascii(24), typeDefs.ascii(24), typeDefs.uint()],
returns: types.ok(types.uint(2000000))
});
// we could also have a addSetupTx(tx: Tx) function
chain.addMock(mockOracle);
const wallet_1 = accounts.get("wallet_1")!;
let block = chain.mineBlock([
Tx.contractCall(`SP000000000000000000002Q6VF78.imaginary-oracle-v1`, "price",
[
types.ascii("usd"),
types.ascii("stx"),
types.uint(5)
], wallet_1.address),
]);
console.info(block)
}) As long as we won't call I think this should give us a bit more pleasant so called developer experience. Clarinet code would look then more or less like this: export interface Accounts extends Map<string, Account> {}
export class Clarinet {
public static test(name: string, fn: (chain:Chain, accounts: Accounts)=> void){
let chain = new Chain(name);
let accounts = chain.accounts;
const testDefinition: Deno.TestDefinition = {
name: name,
fn: async () => {
await fn(chain, accounts);
}
}
Deno.test(testDefinition);
}
}
export class Chain {
sessionId: number;
accounts: Accounts = new Map();
private isReady: boolean = false;
private transactions: Array<Tx> = [];
private name: string;
constructor(name: string) {
this.name = name;
(Deno as any).core.ops();
let result = (Deno as any).core.jsonOpSync("setup_account");
this.sessionId = result["session_id"]
for (let account of result["accounts"]) {
this.accounts.set(account.name, account);
}
}
private setUp() {
let result = (Deno as any).core.jsonOpSync("setup_contracts", {
name: this.name,
transactions: this.transactions
})
// we reset accounts as their balances might be different after this phase
this.accounts.clear();
for (let account of result["accounts"]) {
this.accounts.set(account.name, account);
}
this.isReady = true;
}
addMock(mock: MockContract):void {
this.transactions.push(Tx.deployContract(mock));
}
mineBlock(transactions: Array<Tx>) {
if(!this.isReady) {
this.setUp();
}
let result = (Deno as any).core.jsonOpSync("mine_block", {
sessionId: this.sessionId,
transactions: transactions,
});
let block: Block = {
height: result.block_height,
receipts: result.receipts,
};
return block;
}
....
....
}
|
Interesting idea, although I wonder if this would be clear to people. I can see that people will try to deploy mocks after calling those functions. If one can only deploy mocks during |
The thing is that if your contract somehow depends on a mock, you can't deploy it after. It must be deployed before you can any function in you contract. Otherwise you won't be able to deploy it. Deploying mock is nothing else but part of Clarinet.test({
name: 'name of your test',
preSetup(): Tx[] {
//ARRANGE
// some setup transactions
},
async fn(chain: Chain, accounts: Map<string, Account>) {
//ARRANGE - continuation
//ACT
//ASSERT
}
}); And I think this one is a bit cleaner (only one arrange section): Clarinet.test('name of your test', async (chain: Chain, accounts: Accounts) => {
// ARRANGE
// ACT
// ASSERT
}); Changing mock behavior in the middle of a test? To me it screams for a separate test. |
Point is that people might not be aware of the order of operations and try to deploy a mock after calling
Indeed, which is why I wondered if there is a valid use-case at all.
Yep, I explored this but it leaves things to be desired. You'd need to do some interception and have it call back into a callback defined in test. Sounds tricky. It is why my |
I'm trying to prioritize, is this feature request solving actual pain points? cc @MarvinJanssen @LNow |
I came up with a solution for this with #240, an example is described here: friedger/clarity-catamaranswaps#2. |
@lgalabru this look very nice. manualSetup: async (chain: Chain, accounts: Map<string, Account>, contracts: Map<string, Contract>) => {
const deployer = accounts.get("deployer")!;
chain.mineEmptyBlock(400);
chain.mineBlock([
Tx.deployContract("cool-contract", contracts.get("cool-contract")!.code, deployer.address)
]);
chain.mineBlock([
Tx.contractCall("cool-contract", "init", [], deployer.address)
]);
chain.mineEmptyBlock(10);
chain.mineBlock([
Tx.deployContract("another-contract", contracts.get("another-contract")!.code, deployer.address)
]);
}, It would help simulate more realistic deployments. |
Digging it!
…On Wed, Feb 9, 2022, 10:00 AM LNow ***@***.***> wrote:
@lgalabru <https://github.com/lgalabru> this look very nice.
Would it be possible to add "super advanced" version of it, let's say
manualSetup in which users would have the possibility to manually control
order of deployed contracts and block-height at which they are deployed?
manualSetup: async (chain: Chain, accounts: Map<string, Account>, contracts: Map<string, Contract>) => {
const deployer = accounts.get("deployer")!;
chain.mineEmptyBlock(400);
chain.mineBlock([
Tx.deployContract("cool-contract", contracts.get("cool-contract")!.code, deployer.address)
]);
chain.mineBlock([
Tx.contractCall("cool-contract", "init", [], deployer.address)
]);
chain.mineEmptyBlock(10);
chain.mineBlock([
Tx.deployContract("another-contract", contracts.get("another-contract")!.code, deployer.address)
]);
},
It would help simulate more realistic deployments.
—
Reply to this email directly, view it on GitHub
<#38 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAFPO3LV73PNH5AY64LUZ63U2J6SBANCNFSM46LMGWGQ>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
Addressed in v0.28.0 |
Developers often need to do some initialising work in
preSetup()
, but they cannot access theAccounts
map at this stage. It would be nice if you could.The text was updated successfully, but these errors were encountered: