Skip to content

Commit

Permalink
Merge pull request #1638 from o1-labs/fix/dynamic-call
Browse files Browse the repository at this point in the history
Dynamic call unit test
  • Loading branch information
mitschabaude authored May 6, 2024
2 parents 062a2c4 + 271ec6f commit c8a9c00
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 4 deletions.
92 changes: 92 additions & 0 deletions src/lib/mina/test/dynamic-call.unit-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Tests that shows we can call a subcontract dynamically based on the address,
* as long as its signature matches the signature our contract was compiled against.
*
* In other words, the exact implementation/constraints of zkApp methods we call are not hard-coded in the caller contract.
*/
import {
Bool,
UInt64,
SmartContract,
method,
PublicKey,
Mina,
} from '../../../index.js';

type Subcontract = SmartContract & {
submethod(a: UInt64, b: UInt64): Promise<Bool>;
};

// two implementations with same signature of the called method, but different provable logic

class SubcontractA extends SmartContract implements Subcontract {
@method.returns(Bool)
async submethod(a: UInt64, b: UInt64): Promise<Bool> {
return a.greaterThan(b);
}
}

class SubcontractB extends SmartContract implements Subcontract {
@method.returns(Bool)
async submethod(a: UInt64, b: UInt64): Promise<Bool> {
return a.mul(b).equals(UInt64.from(42));
}
}

// caller contract that calls the subcontract

class Caller extends SmartContract {
@method
async call(a: UInt64, b: UInt64, address: PublicKey) {
const subcontract = new Caller.Subcontract(address);
await subcontract.submethod(a, b);
}

// subcontract to call. this property is changed below
// TODO: having to set this property is a hack, it would be nice to pass the contract as parameter
static Subcontract: new (...args: any) => Subcontract = SubcontractA;
}

// TEST BELOW

// setup

let Local = await Mina.LocalBlockchain({ proofsEnabled: true });
Mina.setActiveInstance(Local);

let [sender, callerAccount, aAccount, bAccount] = Local.testAccounts;

await SubcontractA.compile();
await SubcontractB.compile();
await Caller.compile();

let caller = new Caller(callerAccount);
let a = new SubcontractA(aAccount);
let b = new SubcontractB(bAccount);

await Mina.transaction(sender, async () => {
await caller.deploy();
await a.deploy();
await b.deploy();
})
.sign([callerAccount.key, aAccount.key, bAccount.key, sender.key])
.send();

// subcontract A call

let x = UInt64.from(10);
let y = UInt64.from(5);

await Mina.transaction(sender, () => caller.call(x, y, aAccount))
.prove()
.sign([sender.key])
.send();

// subcontract B call

Caller.Subcontract = SubcontractB;

await Mina.transaction(sender, () => caller.call(x, y, bAccount))
.prove()
.sign([sender.key])
.send();
18 changes: 14 additions & 4 deletions src/lib/mina/zkapp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1612,13 +1612,23 @@ function diffRecursive(
let { transaction, index, accountUpdate: input } = inputData;
diff(transaction, index, prover.toPretty(), input.toPretty());
// TODO
let inputChildren = accountUpdateLayout()!.get(input)!.children.mutable!;
let proverChildren = accountUpdateLayout()!.get(prover)!.children.mutable!;
let proverChildren = accountUpdateLayout()?.get(prover)?.children.mutable;
if (proverChildren === undefined) return;

// collect input children
let inputChildren: AccountUpdate[] = [];
let callDepth = input.body.callDepth;
for (let i = index; i < transaction.accountUpdates.length; i++) {
let update = transaction.accountUpdates[i];
if (update.body.callDepth <= callDepth) break;
if (update.body.callDepth === callDepth + 1) inputChildren.push(update);
}

let nChildren = inputChildren.length;
for (let i = 0; i < nChildren; i++) {
let inputChild = inputChildren[i].mutable;
let inputChild = inputChildren[i];
let child = proverChildren[i].mutable;
if (!inputChild || !child) return;
if (!child) return;
diffRecursive(child, { transaction, index, accountUpdate: inputChild });
}
}
Expand Down

0 comments on commit c8a9c00

Please sign in to comment.