-
Notifications
You must be signed in to change notification settings - Fork 142
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
Hash inputs in JS #310
Hash inputs in JS #310
Changes from all commits
344dc08
33c8d74
e7f383a
29d9291
328d5f9
fef1164
f2a5bd7
1308526
dfe4311
ac8d0aa
0b54f02
5451f3f
9489280
c64443e
7294dfb
704e139
bea057b
01febdb
b1b3913
ed9398f
141be00
15718f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
The mina commit used to generate the backends for node and chrome is | ||
122d163109df05c7295983ebe187e2ad898956a0 | ||
ed1244c761f957ebf99652f28b29411e434048f7 |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
import { | ||
isReady, | ||
Party, | ||
PrivateKey, | ||
Types, | ||
Field, | ||
Ledger, | ||
UInt64, | ||
UInt32, | ||
Experimental, | ||
Bool, | ||
Permissions, | ||
Sign, | ||
Token, | ||
} from 'snarkyjs'; | ||
|
||
await isReady; | ||
|
||
let { asFieldsAndAux, jsLayout, packToFields } = Experimental; | ||
|
||
let party = Party.defaultParty(PrivateKey.random().toPublicKey()); | ||
|
||
// types | ||
type Body = Types.Party['body']; | ||
type Update = Body['update']; | ||
type Timing = Update['timing']['value']; | ||
type AccountPrecondition = Body['preconditions']['account']; | ||
type NetworkPrecondition = Body['preconditions']['network']; | ||
|
||
// timing | ||
let Timing = asFieldsAndAux<Timing, any>( | ||
jsLayout.Party.entries.body.entries.update.entries.timing.inner | ||
); | ||
let timing = party.body.update.timing.value; | ||
timing.initialMinimumBalance = UInt64.one; | ||
timing.vestingPeriod = UInt32.one; | ||
timing.vestingIncrement = UInt64.from(2); | ||
testInput(Timing, Ledger.hashInputFromJson.timing, timing); | ||
|
||
// permissions | ||
let Permissions_ = asFieldsAndAux<Permissions, any>( | ||
jsLayout.Party.entries.body.entries.update.entries.permissions.inner | ||
); | ||
let permissions = party.body.update.permissions; | ||
permissions.isSome = Bool(true); | ||
permissions.value = { | ||
...Permissions.default(), | ||
setVerificationKey: Permissions.none(), | ||
setPermissions: Permissions.none(), | ||
receive: Permissions.proof(), | ||
}; | ||
testInput( | ||
Permissions_, | ||
Ledger.hashInputFromJson.permissions, | ||
permissions.value | ||
); | ||
|
||
// update | ||
let Update = asFieldsAndAux<Update, any>( | ||
jsLayout.Party.entries.body.entries.update | ||
); | ||
let update = party.body.update; | ||
|
||
update.timing.isSome = Bool(true); | ||
update.appState[0].isSome = Bool(true); | ||
update.appState[0].value = Field(9); | ||
update.delegate.isSome = Bool(true); | ||
let delegate = PrivateKey.random().toPublicKey(); | ||
update.delegate.value = delegate; | ||
|
||
party.tokenSymbol.set('BLABLA'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hahaha! This token symbol is funny. |
||
testInput(Update, Ledger.hashInputFromJson.update, update); | ||
|
||
// account precondition | ||
let AccountPrecondition = asFieldsAndAux<AccountPrecondition, any>( | ||
jsLayout.Party.entries.body.entries.preconditions.entries.account | ||
); | ||
let account = party.body.preconditions.account; | ||
party.account.balance.assertEquals(UInt64.from(1e9)); | ||
party.account.isNew.assertEquals(Bool(true)); | ||
party.account.delegate.assertEquals(delegate); | ||
account.state[0].isSome = Bool(true); | ||
account.state[0].value = Field(9); | ||
testInput( | ||
AccountPrecondition, | ||
Ledger.hashInputFromJson.accountPrecondition, | ||
account | ||
); | ||
|
||
// network precondition | ||
let NetworkPrecondition = asFieldsAndAux<NetworkPrecondition, any>( | ||
jsLayout.Party.entries.body.entries.preconditions.entries.network | ||
); | ||
let network = party.body.preconditions.network; | ||
party.network.stakingEpochData.ledger.hash.assertEquals(Field.random()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does invoking assertEquals on a random Field element do here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It changes a precondition on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok that makes sense. |
||
party.network.nextEpochData.lockCheckpoint.assertEquals(Field.random()); | ||
|
||
testInput( | ||
NetworkPrecondition, | ||
Ledger.hashInputFromJson.networkPrecondition, | ||
network | ||
); | ||
|
||
// body | ||
let Body = asFieldsAndAux<Body, any>(jsLayout.Party.entries.body); | ||
let body = party.body; | ||
body.balanceChange.magnitude = UInt64.from(14197832); | ||
body.balanceChange.sgn = Sign.minusOne; | ||
body.callData = Field.random(); | ||
body.callDepth = 1; | ||
body.incrementNonce = Bool(true); | ||
let tokenOwner = PrivateKey.random().toPublicKey(); | ||
body.tokenId = new Token({ tokenOwner }).id; | ||
body.caller = body.tokenId; | ||
testInput(Body, Ledger.hashInputFromJson.body, body); | ||
|
||
// party (should be same as body) | ||
testInput( | ||
Types.Party, | ||
(partyJson) => | ||
Ledger.hashInputFromJson.body(JSON.stringify(JSON.parse(partyJson).body)), | ||
party | ||
); | ||
|
||
console.log('all hash inputs are consistent! 🎉'); | ||
|
||
function testInput<T>( | ||
Module: Experimental.AsFieldsAndAux<T, any>, | ||
toInputOcaml: (json: string) => InputOcaml, | ||
value: T | ||
) { | ||
let json = Module.toJson(value); | ||
// console.log(json); | ||
let input1 = inputFromOcaml(toInputOcaml(JSON.stringify(json))); | ||
let input2 = Module.toInput(value); | ||
// console.log('snarkyjs', JSON.stringify(input2)); | ||
// console.log(); | ||
// console.log('protocol', JSON.stringify(input1)); | ||
let ok1 = JSON.stringify(input2) === JSON.stringify(input1); | ||
// console.log('ok?', ok1); | ||
let fields1 = Ledger.hashInputFromJson.packInput(inputToOcaml(input1)); | ||
let fields2 = packToFields(input2); | ||
let ok2 = JSON.stringify(fields1) === JSON.stringify(fields2); | ||
// console.log('packed ok?', ok2); | ||
// console.log(); | ||
if (!ok1 || !ok2) { | ||
throw Error('inconsistent toInput'); | ||
} | ||
} | ||
|
||
type InputOcaml = { | ||
fields: Field[]; | ||
packed: { field: Field; size: number }[]; | ||
}; | ||
|
||
function inputFromOcaml({ | ||
fields, | ||
packed, | ||
}: { | ||
fields: Field[]; | ||
packed: { field: Field; size: number }[]; | ||
}) { | ||
return { | ||
fields, | ||
packed: packed.map(({ field, size }) => [field, size] as [Field, number]), | ||
}; | ||
} | ||
function inputToOcaml({ | ||
fields, | ||
packed, | ||
}: { | ||
fields: Field[]; | ||
packed: [field: Field, size: number][]; | ||
}) { | ||
return { | ||
fields, | ||
packed: packed.map(([field, size]) => ({ field, size })), | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -139,7 +139,7 @@ function toPermission(p: AuthRequired): Permission { | |
type FetchedAccount = { | ||
publicKey: string; | ||
nonce: string; | ||
tokenId: string; | ||
token: string; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this file has some unrelated fixes which turned up when debugging snarkyjs transactions against a local Mina node, while debugging timestamp preconditions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch on figuring out these fixes! |
||
tokenSymbol: string; | ||
zkappUri?: string; | ||
zkappState: string[] | null; | ||
|
@@ -210,7 +210,7 @@ const accountQuery = (publicKey: string, tokenId: string) => `{ | |
balance { total } | ||
delegateAccount { publicKey } | ||
sequenceEvents | ||
tokenId | ||
token | ||
tokenSymbol | ||
} | ||
} | ||
|
@@ -230,7 +230,7 @@ function parseFetchedAccount({ | |
delegateAccount, | ||
receiptChainHash, | ||
sequenceEvents, | ||
tokenId, | ||
token, | ||
tokenSymbol, | ||
}: Partial<FetchedAccount>): Partial<Account> { | ||
return { | ||
|
@@ -254,7 +254,7 @@ function parseFetchedAccount({ | |
// : undefined, | ||
delegate: | ||
delegateAccount && PublicKey.fromBase58(delegateAccount.publicKey), | ||
tokenId: tokenId !== undefined ? Ledger.fieldOfBase58(tokenId) : undefined, | ||
tokenId: token !== undefined ? Ledger.fieldOfBase58(token) : undefined, | ||
tokenSymbol: tokenSymbol !== undefined ? tokenSymbol : undefined, | ||
}; | ||
} | ||
|
@@ -269,7 +269,7 @@ function stringifyAccount(account: FlexibleAccount): FetchedAccount { | |
zkapp?.appState.map((s) => s.toString()) ?? | ||
Array(ZkappStateLength).fill('0'), | ||
balance: { total: balance?.toString() ?? '0' }, | ||
tokenId: tokenId ?? Ledger.fieldToBase58(getDefaultTokenId()), | ||
token: tokenId ?? Ledger.fieldToBase58(getDefaultTokenId()), | ||
tokenSymbol: tokenSymbol ?? '', | ||
}; | ||
} | ||
|
@@ -384,7 +384,7 @@ function addCachedAccountInternal( | |
account: FetchedAccount, | ||
graphqlEndpoint: string | ||
) { | ||
accountCache[`${account.publicKey};${account.tokenId};${graphqlEndpoint}`] = { | ||
accountCache[`${account.publicKey};${account.token};${graphqlEndpoint}`] = { | ||
account, | ||
graphqlEndpoint, | ||
timestamp: Date.now(), | ||
|
@@ -570,6 +570,7 @@ function removeJsonQuotes(json: string) { | |
); | ||
} | ||
|
||
// TODO it seems we're not actually catching most errors here | ||
async function makeGraphqlRequest( | ||
query: string, | ||
graphqlEndpoint = defaultGraphqlEndpoint, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a sort of unit test, which is also run in Mina CI. I left it here just because for the Mina version, I had to remove the TS types, and it's easier to read & modify with the types in place