Skip to content

Commit

Permalink
Merge pull request #1784 from o1-labs/multi-actions-order
Browse files Browse the repository at this point in the history
Correcting order for actions occuring within the same block for the same account
  • Loading branch information
45930 authored Aug 19, 2024
2 parents 72a2779 + 599fe06 commit 721ca6a
Show file tree
Hide file tree
Showing 13 changed files with 539 additions and 92 deletions.
9 changes: 9 additions & 0 deletions run-ci-live-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ echo ""

./run src/examples/zkapps/hello-world/run-live.ts --bundle | add_prefix "HELLO_WORLD" &
HELLO_WORLD_PROC=$!
./run src/examples/zkapps/reducer/run-live.ts --bundle | add_prefix "REDUCER" &
REDUCER_FLOW_PROC=$!
./run src/examples/zkapps/dex/run-live.ts --bundle | add_prefix "DEX" &
DEX_PROC=$!
./run src/examples/fetch-live.ts --bundle | add_prefix "FETCH" &
Expand Down Expand Up @@ -52,6 +54,13 @@ if [ $? -ne 0 ]; then
echo ""
FAILURE=1
fi
wait $REDUCER_FLOW_PROC
if [ $? -ne 0 ]; then
echo ""
echo "REDUCER_FLOW test failed."
echo ""
FAILURE=1
fi

# Exit with failure if any process failed
if [ $FAILURE -ne 0 ]; then
Expand Down
3 changes: 1 addition & 2 deletions run-ci-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ case $TEST_TYPE in

"Reducer integration tests")
echo "Running reducer integration tests"
./run src/examples/zkapps/reducer/actions-as-merkle-list.ts --bundle
./run src/examples/zkapps/reducer/actions-as-merkle-list-iterator.ts --bundle
./run src/examples/zkapps/reducer/run.ts --bundle
;;

"Voting integration tests")
Expand Down
9 changes: 9 additions & 0 deletions src/examples/utils/network-configuration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export {
DEFAULT_LIGHTNET_CONFIG
}

const DEFAULT_LIGHTNET_CONFIG = {
mina: 'http://localhost:8080/graphql',
archive: 'http://localhost:8282',
lightnetAccountManager: 'http://localhost:8181',
}
23 changes: 23 additions & 0 deletions src/examples/utils/random-accounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { PrivateKey, PublicKey } from 'o1js';

export {
randomAccounts
}

/**
* Predefined accounts keys, labeled by the input strings. Useful for testing/debugging with consistent keys.
*/
function randomAccounts<K extends string>(
...names: [K, ...K[]]
): { keys: Record<K, PrivateKey>; addresses: Record<K, PublicKey> } {
let base58Keys = Array(names.length)
.fill('')
.map(() => PrivateKey.random().toBase58());
let keys = Object.fromEntries(
names.map((name, idx) => [name, PrivateKey.fromBase58(base58Keys[idx])])
) as Record<K, PrivateKey>;
let addresses = Object.fromEntries(
names.map((name) => [name, keys[name].toPublicKey()])
) as Record<K, PublicKey>;
return { keys, addresses };
}
72 changes: 38 additions & 34 deletions src/examples/zkapps/reducer/actions-as-merkle-list-iterator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
*
* This is mainly intended as an example for using `Iterator` and `MerkleList`, but it might also be useful as
* a blueprint for processing actions in a custom and more explicit way.
*
* Warning: The reducer API in o1js is currently not safe to use in production applications. The `reduce()`
* method breaks if more than the hard-coded number (default: 32) of actions are pending. Work is actively
*
* Warning: The reducer API in o1js is currently not safe to use in production applications. The `reduce()`
* method breaks if more than the hard-coded number (default: 32) of actions are pending. Work is actively
* in progress to mitigate this limitation.
*/
*/
import {
Field,
Mina,
Expand All @@ -20,6 +20,8 @@ import {
assert,
} from 'o1js';

export { ActionsContract, testLocal };

// constants for our static-sized provable code
const MAX_UPDATES_WITH_ACTIONS = 100;
const MAX_ACTIONS_PER_UPDATE = 2;
Expand Down Expand Up @@ -81,44 +83,46 @@ class ActionsContract extends SmartContract {

// TESTS

// set up a local blockchain
async function testLocal() {
// set up a local blockchain

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

let [sender, contractAddress] = Local.testAccounts;
let [sender, contractAddress] = Local.testAccounts.slice(4);

let contract = new ActionsContract(contractAddress);
let contract = new ActionsContract(contractAddress);

// deploy the contract
// deploy the contract

await ActionsContract.compile();
console.log(
`rows for ${MAX_UPDATES_WITH_ACTIONS} updates with actions`,
(await ActionsContract.analyzeMethods()).accumulate.rows
);
let deployTx = await Mina.transaction(sender, async () => contract.deploy());
await deployTx.sign([sender.key, contractAddress.key]).send();
await ActionsContract.compile();
console.log(
`rows for ${MAX_UPDATES_WITH_ACTIONS} updates with actions`,
(await ActionsContract.analyzeMethods()).accumulate.rows
);
let deployTx = await Mina.transaction(sender, async () => contract.deploy());
await deployTx.sign([sender.key, contractAddress.key]).send();

// push some actions
// push some actions

let dispatchTx = await Mina.transaction(sender, async () => {
await contract.increment(Field(1));
await contract.increment(Field(3));
await contract.increment(Field(5));
await contract.increment(Field(9));
await contract.twoIncrements(Field(18), Field(19));
});
await dispatchTx.prove();
await dispatchTx.sign([sender.key]).send();
let dispatchTx = await Mina.transaction(sender, async () => {
await contract.increment(Field(1));
await contract.increment(Field(3));
await contract.increment(Field(5));
await contract.increment(Field(9));
await contract.twoIncrements(Field(18), Field(19));
});
await dispatchTx.prove();
await dispatchTx.sign([sender.key]).send();

assert(contract.reducer.getActions().data.get().length === 5);
assert(contract.reducer.getActions().data.get().length === 5);

// accumulate actions
// accumulate actions

Local.setProofsEnabled(true);
let accTx = await Mina.transaction(sender, () => contract.accumulate());
await accTx.prove();
await accTx.sign([sender.key]).send();
Local.setProofsEnabled(true);
let accTx = await Mina.transaction(sender, () => contract.accumulate());
await accTx.prove();
await accTx.sign([sender.key]).send();

assert(contract.counter.get().toBigInt() === 55n);
assert(contract.counter.get().toBigInt() === 55n);
}
75 changes: 39 additions & 36 deletions src/examples/zkapps/reducer/actions-as-merkle-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
*
* This is mainly intended as an example for using `MerkleList`, but it might also be useful as
* a blueprint for processing actions in a custom and more explicit way.
*
* Warning: The reducer API in o1js is currently not safe to use in production applications. The `reduce()`
* method breaks if more than the hard-coded number (default: 32) of actions are pending. Work is actively
*
* Warning: The reducer API in o1js is currently not safe to use in production applications. The `reduce()`
* method breaks if more than the hard-coded number (default: 32) of actions are pending. Work is actively
* in progress to mitigate this limitation.
*/
*/
import {
Bool,
Mina,
Expand All @@ -19,6 +19,8 @@ import {
assert,
} from 'o1js';

export { MerkleListReducing, testLocal };

// in this example, an action is just a public key
type Action = PublicKey;
const Action = PublicKey;
Expand Down Expand Up @@ -64,7 +66,6 @@ class MerkleListReducing extends SmartContract {
hasAddress = hasAddress.or(action.equals(address));
}
}

assert(actions.isEmpty()); // we processed all actions
assert(hasAddress); // we found the address
}
Expand All @@ -74,43 +75,45 @@ class MerkleListReducing extends SmartContract {

// set up a local blockchain

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

let [sender, contractAccount, otherAddress, anotherAddress] =
Local.testAccounts;
let [sender, contractAccount, otherAddress, anotherAddress] =
Local.testAccounts;

let contract = new MerkleListReducing(contractAccount);
let contract = new MerkleListReducing(contractAccount);

// deploy the contract
// deploy the contract

await MerkleListReducing.compile();
console.log(
`rows for ${MAX_UPDATES_WITH_ACTIONS} updates with actions`,
(await MerkleListReducing.analyzeMethods()).assertContainsAddress.rows
);
let deployTx = await Mina.transaction(sender, async () => contract.deploy());
await deployTx.sign([sender.key, contractAccount.key]).send();
await MerkleListReducing.compile();
console.log(
`rows for ${MAX_UPDATES_WITH_ACTIONS} updates with actions`,
(await MerkleListReducing.analyzeMethods()).assertContainsAddress.rows
);
let deployTx = await Mina.transaction(sender, async () => contract.deploy());
await deployTx.sign([sender.key, contractAccount.key]).send();

// push some actions
// push some actions

let dispatchTx = await Mina.transaction(sender, async () => {
await contract.postAddress(otherAddress);
await contract.postAddress(contractAccount);
await contract.postTwoAddresses(anotherAddress, sender);
await contract.postAddress(anotherAddress);
await contract.postTwoAddresses(contractAccount, otherAddress);
});
await dispatchTx.prove();
await dispatchTx.sign([sender.key]).send();
let dispatchTx = await Mina.transaction(sender, async () => {
await contract.postAddress(otherAddress);
await contract.postAddress(contractAccount);
await contract.postTwoAddresses(anotherAddress, sender);
await contract.postAddress(anotherAddress);
await contract.postTwoAddresses(contractAccount, otherAddress);
});
await dispatchTx.prove();
await dispatchTx.sign([sender.key]).send();

assert(contract.reducer.getActions().data.get().length === 5);
assert(contract.reducer.getActions().data.get().length === 5);

// check if the actions contain the `sender` address
// check if the actions contain the `sender` address

Local.setProofsEnabled(true);
let containsTx = await Mina.transaction(sender, () =>
contract.assertContainsAddress(sender)
);
await containsTx.prove();
await containsTx.sign([sender.key]).send();
Local.setProofsEnabled(true);
let containsTx = await Mina.transaction(sender, () =>
contract.assertContainsAddress(sender)
);
await containsTx.prove();
await containsTx.sign([sender.key]).send();
}
Loading

0 comments on commit 721ca6a

Please sign in to comment.