Skip to content
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

Missed part of the Mainnet support. #1437

Merged
merged 15 commits into from
Feb 16, 2024
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
_Security_ in case of vulnerabilities.
-->

## [Unreleased](https://github.com/o1-labs/o1js/compare/834a44002...HEAD)
## [Unreleased](https://github.com/o1-labs/o1js/compare/3b5f7c7...HEAD)

## [0.16.1](https://github.com/o1-labs/o1js/compare/834a44002...3b5f7c7)

### Breaking changes

Expand All @@ -35,6 +37,10 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- `TokenAccountUpdateIterator`, a primitive to iterate over all token account updates in a transaction https://github.com/o1-labs/o1js/pull/1398
- this is used to implement `TokenContract` under the hood

### Fixed

- Mainnet support. https://github.com/o1-labs/o1js/pull/1437

## [0.16.0](https://github.com/o1-labs/o1js/compare/e5d1e0f...834a44002)

### Breaking changes
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "o1js",
"description": "TypeScript framework for zk-SNARKs and zkApps",
"version": "0.16.0",
"version": "0.16.1",
"license": "Apache-2.0",
"homepage": "https://github.com/o1-labs/o1js/",
"keywords": [
Expand Down
28 changes: 23 additions & 5 deletions src/lib/account-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1017,10 +1017,20 @@ class AccountUpdate implements Types.AccountUpdate {
// implementations are equivalent, and catch regressions quickly
if (Provable.inCheckedComputation()) {
let input = Types.AccountUpdate.toInput(this);
return hashWithPrefix(prefixes.body, packToFields(input));
return hashWithPrefix(
activeInstance.getNetworkId() === 'mainnet'
? prefixes.zkappBodyMainnet
: prefixes.zkappBodyTestnet,
packToFields(input)
);
} else {
let json = Types.AccountUpdate.toJSON(this);
return Field(Test.hashFromJson.accountUpdate(JSON.stringify(json)));
return Field(
Test.hashFromJson.accountUpdate(
JSON.stringify(json),
activeInstance.getNetworkId()
)
);
}
}

Expand Down Expand Up @@ -1048,7 +1058,8 @@ class AccountUpdate implements Types.AccountUpdate {
forest,
(a) => a.hash(),
Poseidon.hashWithPrefix,
emptyHash
emptyHash,
activeInstance.getNetworkId()
);
return { accountUpdate, calls };
}
Expand Down Expand Up @@ -1386,7 +1397,13 @@ class AccountUpdate implements Types.AccountUpdate {
// call forest stuff

function hashAccountUpdate(update: AccountUpdate) {
return genericHash(AccountUpdate, prefixes.body, update);
return genericHash(
AccountUpdate,
activeInstance.getNetworkId() === 'mainnet'
? prefixes.zkappBodyMainnet
: prefixes.zkappBodyTestnet,
update
);
}

class HashedAccountUpdate extends Hashed.create(
Expand Down Expand Up @@ -1983,7 +2000,8 @@ function addMissingSignatures(
): ZkappCommandSigned {
let additionalPublicKeys = additionalKeys.map((sk) => sk.toPublicKey());
let { commitment, fullCommitment } = transactionCommitments(
TypesBigint.ZkappCommand.fromJSON(ZkappCommand.toJSON(zkappCommand))
TypesBigint.ZkappCommand.fromJSON(ZkappCommand.toJSON(zkappCommand)),
activeInstance.getNetworkId()
);

function addFeePayerSignature(accountUpdate: FeePayerUnsigned): FeePayer {
Expand Down
3 changes: 2 additions & 1 deletion src/lib/mina.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,8 @@ function LocalBlockchain({

let zkappCommandJson = ZkappCommand.toJSON(txn.transaction);
let commitments = transactionCommitments(
TypesBigint.ZkappCommand.fromJSON(zkappCommandJson)
TypesBigint.ZkappCommand.fromJSON(zkappCommandJson),
minaNetworkId
);

if (enforceTransactionLimits) verifyTransactionLimits(txn.transaction);
Expand Down
2 changes: 1 addition & 1 deletion src/lib/mina/token/forest-iterator.unit-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ test.custom({ timeBudget: 1000 })(
(flatUpdatesBigint) => {
// reference: bigint callforest hash from mina-signer
let forestBigint = accountUpdatesToCallForest(flatUpdatesBigint);
let expectedHash = callForestHash(forestBigint);
let expectedHash = callForestHash(forestBigint, 'testnet');

let flatUpdates = flatUpdatesBigint.map(accountUpdateFromBigint);
let forest = AccountUpdateForest.fromFlatArray(flatUpdates);
Expand Down
4 changes: 2 additions & 2 deletions src/mina-signer/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/mina-signer/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "mina-signer",
"description": "Node API for signing transactions on various networks for Mina Protocol",
"version": "3.0.0",
"version": "3.0.1",
"type": "module",
"scripts": {
"build": "tsc -p ../../tsconfig.mina-signer.json",
Expand Down
62 changes: 47 additions & 15 deletions src/mina-signer/src/sign-zkapp-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ function signZkappCommand(
): Json.ZkappCommand {
let zkappCommand = ZkappCommand.fromJSON(zkappCommand_);

let { commitment, fullCommitment } = transactionCommitments(zkappCommand);
let { commitment, fullCommitment } = transactionCommitments(
zkappCommand,
networkId
);
let privateKey = PrivateKey.fromBase58(privateKeyBase58);
let publicKey = zkappCommand.feePayer.body.publicKey;

Expand All @@ -71,7 +74,10 @@ function verifyZkappCommandSignature(
) {
let zkappCommand = ZkappCommand.fromJSON(zkappCommand_);

let { commitment, fullCommitment } = transactionCommitments(zkappCommand);
let { commitment, fullCommitment } = transactionCommitments(
zkappCommand,
networkId
);
let publicKey = PublicKey.fromBase58(publicKeyBase58);

// verify fee payer signature
Expand Down Expand Up @@ -108,14 +114,17 @@ function verifyAccountUpdateSignature(
return verifyFieldElement(signature, usedCommitment, publicKey, networkId);
}

function transactionCommitments(zkappCommand: ZkappCommand) {
function transactionCommitments(
zkappCommand: ZkappCommand,
networkId: NetworkId
) {
if (!isCallDepthValid(zkappCommand)) {
throw Error('zkapp command: invalid call depth');
}
let callForest = accountUpdatesToCallForest(zkappCommand.accountUpdates);
let commitment = callForestHash(callForest);
let commitment = callForestHash(callForest, networkId);
let memoHash = Memo.hash(Memo.fromBase58(zkappCommand.memo));
let feePayerDigest = feePayerHash(zkappCommand.feePayer);
let feePayerDigest = feePayerHash(zkappCommand.feePayer, networkId);
let fullCommitment = hashWithPrefix(prefixes.accountUpdateCons, [
memoHash,
feePayerDigest,
Expand Down Expand Up @@ -150,32 +159,55 @@ function accountUpdatesToCallForest<A extends { body: { callDepth: number } }>(
return forest;
}

function accountUpdateHash(update: AccountUpdate) {
const zkAppBodyPrefix = (network: string) => {
switch (network) {
case 'mainnet':
return prefixes.zkappBodyMainnet;
case 'testnet':
return prefixes.zkappBodyTestnet;

default:
return 'ZkappBody' + network;
}
};

function accountUpdateHash(update: AccountUpdate, networkId: NetworkId) {
assertAuthorizationKindValid(update);
let input = AccountUpdate.toInput(update);
let fields = packToFields(input);
return hashWithPrefix(prefixes.body, fields);
return hashWithPrefix(zkAppBodyPrefix(networkId), fields);
}

function callForestHash(forest: CallForest<AccountUpdate>): bigint {
return callForestHashGeneric(forest, accountUpdateHash, hashWithPrefix, 0n);
function callForestHash(
forest: CallForest<AccountUpdate>,
networkId: NetworkId
): bigint {
return callForestHashGeneric(
forest,
accountUpdateHash,
hashWithPrefix,
0n,
networkId
);
}

function callForestHashGeneric<A, F>(
forest: CallForest<A>,
hash: (a: A) => F,
hash: (a: A, networkId: NetworkId) => F,
hashWithPrefix: (prefix: string, input: F[]) => F,
emptyHash: F
emptyHash: F,
networkId: NetworkId
): F {
let stackHash = emptyHash;
for (let callTree of [...forest].reverse()) {
let calls = callForestHashGeneric(
callTree.children,
hash,
hashWithPrefix,
emptyHash
emptyHash,
networkId
);
let treeHash = hash(callTree.accountUpdate);
let treeHash = hash(callTree.accountUpdate, networkId);
let nodeHash = hashWithPrefix(prefixes.accountUpdateNode, [
treeHash,
calls,
Expand All @@ -193,9 +225,9 @@ type FeePayer = ZkappCommand['feePayer'];
function createFeePayer(feePayer: FeePayer['body']): FeePayer {
return { authorization: '', body: feePayer };
}
function feePayerHash(feePayer: FeePayer) {
function feePayerHash(feePayer: FeePayer, networkId: NetworkId) {
let accountUpdate = accountUpdateFromFeePayer(feePayer);
return accountUpdateHash(accountUpdate);
return accountUpdateHash(accountUpdate, networkId);
}

function accountUpdateFromFeePayer({
Expand Down
Loading
Loading